Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> the same name.</li>
*
* <li>will not return internal or external attributes.</li>
*
* <li>may return incomplete extra field data.</li>
*
* <li>may return unknown sizes and CRC values for entries until the
* next entry has been reached if the archive uses the data
* descriptor feature.</li>
*
* </ul>
*
* @see ZipFile
* @NotThreadSafe
*/
public class ZipArchiveInputStream extends ArchiveInputStream {
/** The zip encoding to use for filenames and the file comment. */
private final ZipEncoding zipEncoding;
// the provided encoding (for unit tests)
final String encoding;
/** Whether to look for and use Unicode extra fields. */
private final boolean useUnicodeExtraFields;
/** Wrapped stream, will always be a PushbackInputStream. */
private final InputStream in;
/** Inflater used for all deflated entries. */
private final Inflater inf = new Inflater(true);
/** Buffer used to read from the wrapped stream. */
private final ByteBuffer buf = ByteBuffer.allocate(ZipArchiveOutputStream.BUFFER_SIZE);
/** The entry that is currently being read. */
private CurrentEntry current = null;
/** Whether the stream has been closed. */
private boolean closed = false;
/** Whether the stream has reached the central directory - and thus found all entries. */
private boolean hitCentralDirectory = false;
/**
* When reading a stored entry that uses the data descriptor this
* stream has to read the full entry and caches it. This is the
* cache.
*/
private ByteArrayInputStream lastStoredEntry = null;
/** Whether the stream will try to read STORED entries that use a data descriptor. */
private boolean allowStoredEntriesWithDataDescriptor = false;
private static final int LFH_LEN = 30;
/*
local file header signature WORD
version needed to extract SHORT
general purpose bit flag SHORT
compression method SHORT
last mod file time SHORT
last mod file date SHORT
crc-32 WORD
compressed size WORD
uncompressed size WORD
file name length SHORT
extra field length SHORT
*/
private static final int CFH_LEN = 46;
/*
central file header signature WORD
version made by SHORT
version needed to extract SHORT
general purpose bit flag SHORT
compression method SHORT
last mod file time SHORT
last mod file date SHORT
crc-32 WORD
compressed size WORD
uncompressed size WORD
file name length SHORT
extra field length SHORT
file comment length SHORT
disk number start SHORT
internal file attributes SHORT
external file attributes WORD
relative offset of local header WORD
*/
private static final long TWO_EXP_32 = ZIP64_MAGIC + 1;
// cached buffers - must only be used locally in the class (COMPRESS-172 - reduce garbage collection)
private
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> final byte[] LFH_BUF = new byte[LFH_LEN];
private final byte[] SKIP_BUF = new byte[1024];
private final byte[] SHORT_BUF = new byte[SHORT];
private final byte[] WORD_BUF = new byte[WORD];
private final byte[] TWO_DWORD_BUF = new byte[2 * DWORD];
private int entriesRead = 0;
/**
* Create an instance using UTF-8 encoding
* @param inputStream the stream to wrap
*/
public ZipArchiveInputStream(final InputStream inputStream) {
this(inputStream, ZipEncodingHelper.UTF8);
}
/**
* Create an instance using the specified encoding
* @param inputStream the stream to wrap
* @param encoding the encoding to use for file names, use null
* for the platform's default encoding
* @since 1.5
*/
public ZipArchiveInputStream(final InputStream inputStream, final String encoding) {
this(inputStream, encoding, true);
}
/**
* Create an instance using the specified encoding
* @param inputStream the stream to wrap
* @param encoding the encoding to use for file names, use null
* for the platform's default encoding
* @param useUnicodeExtraFields whether to use InfoZIP Unicode
* Extra Fields (if present) to set the file names.
*/
public ZipArchiveInputStream(final InputStream inputStream, final String encoding, final boolean useUnicodeExtraFields) {
this(inputStream, encoding, useUnicodeExtraFields, false);
}
/**
* Create an instance using the specified encoding
* @param inputStream the stream to wrap
* @param encoding the encoding to use for file names, use null
* for the platform's default encoding
* @param useUnicodeExtraFields whether to use InfoZIP Unicode
* Extra Fields (if present) to set the file names.
* @param allowStoredEntriesWithDataDescriptor whether the stream
* will try to read STORED entries that use a data descriptor
* @since 1.1
*/
public ZipArchiveInputStream(final InputStream inputStream,
final String encoding,
final boolean useUnicodeExtraFields,
final boolean allowStoredEntriesWithDataDescriptor) {
this.encoding = encoding;
zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
this.useUnicodeExtraFields = useUnicodeExtraFields;
in = new PushbackInputStream(inputStream, buf.capacity());
this.allowStoredEntriesWithDataDescriptor =
allowStoredEntriesWithDataDescriptor;
// haven't read anything so far
buf.limit(0);
}
public ZipArchiveEntry getNextZipEntry() throws IOException {
boolean firstEntry = true;
if (closed || hitCentralDirectory) {
return null;
}
if (current != null) {
closeEntry();
firstEntry = false;
current.entry.setMethod(ZipShort.getValue(LFH_BUF, off));
off += SHORT;
final long time = ZipUtil.dosToJavaTime(ZipLong.getValue(LFH_BUF, off));
current.entry.setTime(time);
off += WORD;
ZipLong
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> if (current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()
|| current.entry.getMethod() == ZipMethod.IMPLODING.getCode()
|| current.entry.getMethod() == ZipMethod.BZIP2.getCode()) {
read = current.in.read(buffer, offset, length);
} else {
throw new UnsupportedZipFeatureException(ZipMethod.getMethodByCode(current.entry.getMethod()),
current.entry);
}
if (read >= 0) {
current.crc.update(buffer, offset, read);
}
return read;
}
/**
* Implementation of read for STORED entries.
*/
private int readStored(final byte[] buffer, final int offset, final int length) throws IOException {
if (current.hasDataDescriptor) {
if (lastStoredEntry == null) {
readStoredEntry();
}
return lastStoredEntry.read(buffer, offset, length);
}
final long csize = current.entry.getSize();
if (current.bytesRead >= csize) {
return -1;
}
if (buf.position() >= buf.limit()) {
buf.position(0);
final int l = in.read(buf.array());
if (l == -1) {
return -1;
}
buf.limit(l);
count(l);
current.bytesReadFromStream += l;
}
int toRead = Math.min(buf.remaining(), length);
if ((csize - current.bytesRead) < toRead) {
// if it is smaller than toRead then it fits into an int
toRead = (int) (csize - current.bytesRead);
}
buf.get(buffer, offset, toRead);
current.bytesRead += toRead;
return toRead;
}
/**
* Implementation of read for DEFLATED entries.
*/
private int readDeflated(final byte[] buffer, final int offset, final int length) throws IOException {
final int read = readFromInflater(buffer, offset, length);
if (read <= 0) {
if (inf.finished()) {
return -1;
} else if (inf.needsDictionary()) {
throw new ZipException("This archive needs a preset dictionary"
+ " which is not supported by Commons"
+ " Compress.");
} else if (read == -1) {
throw new IOException("Truncated ZIP file");
}
}
return read;
}
/**
* Potentially reads more bytes to fill the inflater's buffer and
* reads from it.
*/
private int readFromInflater(final byte[] buffer, final int offset, final int length) throws IOException {
int read = 0;
do {
if (inf.needsInput()) {
final int l = fill();
if (l > 0) {
current.bytesReadFromStream += buf.limit();
} else if (l == -1) {
return -1;
} else {
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> break;
}
}
try {
read = inf.inflate(buffer, offset, length);
} catch (final DataFormatException e) {
throw (IOException) new ZipException(e.getMessage()).initCause(e);
}
} while (read == 0 && inf.needsInput());
return read;
}
@Override
public void close() throws IOException {
if (!closed) {
closed = true;
try {
in.close();
} finally {
inf.end();
}
}
}
/**
* Skips over and discards value bytes of data from this input
* stream.
*
* <p>This implementation may end up skipping over some smaller
* number of bytes, possibly 0, if and only if it reaches the end
* of the underlying stream.</p>
*
* <p>The actual number of bytes skipped is returned.</p>
*
* @param value the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @throws IOException - if an I/O error occurs.
* @throws IllegalArgumentException - if value is negative.
*/
@Override
public long skip(final long value) throws IOException {
if (value >= 0) {
long skipped = 0;
while (skipped < value) {
final long rem = value - skipped;
final int x = read(SKIP_BUF, 0, (int) (SKIP_BUF.length > rem ? rem : SKIP_BUF.length));
if (x == -1) {
return skipped;
}
skipped += x;
}
return skipped;
}
throw new IllegalArgumentException();
}
/**
* Checks if the signature matches what is expected for a zip file.
* Does not currently handle self-extracting zips which may have arbitrary
* leading content.
*
* @param signature the bytes to check
* @param length the number of bytes to check
* @return true, if this stream is a zip archive stream, false otherwise
*/
public static boolean matches(final byte[] signature, final int length) {
if (length < ZipArchiveOutputStream.LFH_SIG.length) {
return false;
}
return checksig(signature, ZipArchiveOutputStream.LFH_SIG) // normal file
|| checksig(signature, ZipArchiveOutputStream.EOCD_SIG) // empty zip
|| checksig(signature, ZipArchiveOutputStream.DD_SIG) // split zip
|| checksig(signature, ZipLong.SINGLE_SEGMENT_SPLIT_MARKER.getBytes());
}
private static boolean checksig(final byte[] signature, final byte[] expected) {
for (int i = 0; i < expected.length; i++) {
if (signature[i] != expected[i]) {
return false;
}
}
return true;
}
/**
* Closes the current ZIP archive entry and positions the underlying
* stream to the beginning of the next entry. All per-entry variables
* and data structures are cleared.
*
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> this extra field
*/
@Override
public ZipShort getCentralDirectoryLength() {
return ZERO;
}
/**
* The actual data to put into local file data - without Header-ID
* or length specifier.
*
* @return get the data
*/
@Override
public byte[] getLocalFileDataData() {
byte[] uidBytes = uid.toByteArray();
byte[] gidBytes = gid.toByteArray();
// BigInteger might prepend a leading-zero to force a positive representation
// (e.g., so that the sign-bit is set to zero). We need to remove that
// before sending the number over the wire.
uidBytes = trimLeadingZeroesForceMinLength(uidBytes);
gidBytes = trimLeadingZeroesForceMinLength(gidBytes);
// Couldn't bring myself to just call getLocalFileDataLength() when we've
// already got the arrays right here. Yeah, yeah, I know, premature
// optimization is the root of all...
//
// The 3 comes from: version=1 + uidsize=1 + gidsize=1
final byte[] data = new byte[3 + uidBytes.length + gidBytes.length];
// reverse() switches byte array from big-endian to little-endian.
reverse(uidBytes);
reverse(gidBytes);
int pos = 0;
data[pos++] = unsignedIntToSignedByte(version);
data[pos++] = unsignedIntToSignedByte(uidBytes.length);
System.arraycopy(uidBytes, 0, data, pos, uidBytes.length);
pos += uidBytes.length;
data[pos++] = unsignedIntToSignedByte(gidBytes.length);
System.arraycopy(gidBytes, 0, data, pos, gidBytes.length);
return data;
}
/**
* The actual data to put into central directory data - without Header-ID
* or length specifier.
*
* @return get the data
*/
@Override
public byte[] getCentralDirectoryData() {
return new byte[0];
}
/**
* Populate data from this array as if it was in local file data.
*
* @param data an array of bytes
* @param offset the start offset
* @param length the number of bytes in the array from offset
* @throws java.util.zip.ZipException on error
*/
@Override
public void parseFromLocalFileData(
final byte[] data, int offset, final int length
) throws ZipException {
reset();
this.version = signedByteToUnsignedInt(data[offset++]);
final int uidSize = signedByteToUnsignedInt(data[offset++]);
final byte[] uidBytes = new byte[uidSize];
System.arraycopy(data, offset, uidBytes, 0, uidSize);
offset += uidSize;
this.uid = new BigInteger(1, reverse(uidBytes)); // sign-bit forced positive
final int gidSize = signedByteToUnsignedInt(data[offset++]);
final
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> byte[] gidBytes = new byte[gidSize];
System.arraycopy(data, offset, gidBytes, 0, gidSize);
this.gid = new BigInteger(1, reverse(gidBytes)); // sign-bit forced positive
}
/**
* Doesn't do anything since this class doesn't store anything
* inside the central directory.
*/
@Override
public void parseFromCentralDirectoryData(
final byte[] buffer, final int offset, final int length
) throws ZipException {
}
/**
* Reset state back to newly constructed state. Helps us make sure
* parse() calls always generate clean results.
*/
private void reset() {
// Typical UID/GID of the first non-root user created on a unix system.
uid = ONE_THOUSAND;
gid = ONE_THOUSAND;
}
/**
* Returns a String representation of this class useful for
* debugging purposes.
*
* @return A String representation of this class useful for
* debugging purposes.
*/
@Override
public String toString() {
return "0x7875 Zip Extra Field: UID=" + uid + " GID=" + gid;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public boolean equals(final Object o) {
if (o instanceof X7875_NewUnix) {
final X7875_NewUnix xf = (X7875_NewUnix) o;
// We assume uid and gid can never be null.
return version == xf.version && uid.equals(xf.uid) && gid.equals(xf.gid);
}
return false;
}
@Override
public int hashCode() {
int hc = -1234567 * version;
// Since most UID's and GID's are below 65,536, this is (hopefully!)
// a nice way to make sure typical UID and GID values impact the hash
// as much as possible.
hc ^= Integer.rotateLeft(uid.hashCode(), 16);
hc ^= gid.hashCode();
return hc;
}
/**
* Not really for external usage, but marked "package" visibility
* to help us JUnit it. Trims a byte array of leading zeroes while
* also enforcing a minimum length, and thus it really trims AND pads
* at the same time.
*
* @param array byte[] array to trim & pad.
* @return trimmed & padded byte[] array.
*/
static byte[] trimLeadingZeroesForceMinLength(final byte[] array) {
if (array == null) {
return array;
}
int pos = 0;
for (final byte b : array) {
if (b == 0) {
pos++;
} else {
break;
}
}
/*
I agonized over my choice of MIN_LENGTH=1. Here's the situation
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>and call their
* implementation from super of course).
*
* Compressing a ZIP-File:
*
* <pre>
* final OutputStream out = new FileOutputStream(output);
* ArchiveOutputStream os = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP, out);
*
* os.putArchiveEntry(new ZipArchiveEntry("testdata/test1.xml"));
* IOUtils.copy(new FileInputStream(file1), os);
* os.closeArchiveEntry();
*
* os.putArchiveEntry(new ZipArchiveEntry("testdata/test2.xml"));
* IOUtils.copy(new FileInputStream(file2), os);
* os.closeArchiveEntry();
* os.close();
* </pre>
*
* Decompressing a ZIP-File:
*
* <pre>
* final InputStream is = new FileInputStream(input);
* ArchiveInputStream in = new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP, is);
* ZipArchiveEntry entry = (ZipArchiveEntry)in.getNextEntry();
* OutputStream out = new FileOutputStream(new File(dir, entry.getName()));
* IOUtils.copy(in, out);
* out.close();
* in.close();
* </pre>
* @Immutable provided that the deprecated method setEntryEncoding is not used.
* @ThreadSafe even if the deprecated method setEntryEncoding is used
*/
public class ArchiveStreamFactory implements ArchiveStreamProvider {
private static final int TAR_HEADER_SIZE = 512;
private static final int DUMP_SIGNATURE_SIZE = 32;
private static final int SIGNATURE_SIZE = 12;
private static final ArchiveStreamFactory SINGLETON = new ArchiveStreamFactory();
/**
* Constant (value {@value}) used to identify the AR archive format.
* @since 1.1
*/
public static final String AR = "ar";
/**
* Constant (value {@value}) used to identify the ARJ archive format.
* Not supported as an output stream type.
* @since 1.6
*/
public static final String ARJ = "arj";
/**
* Constant (value {@value}) used to identify the CPIO archive format.
* @since 1.1
*/
public static final String CPIO = "cpio";
/**
* Constant (value {@value}) used to identify the Unix DUMP archive format.
* Not supported as an output stream type.
* @since 1.3
*/
public static final String DUMP = "dump";
/**
* Constant (value {@value}) used to identify the JAR archive format.
* @since 1.1
*/
public static final String JAR = "jar";
/**
* Constant used to identify the TAR archive format.
* @since 1.1
*/
public static final String TAR = "tar";
/**
* Constant (value {@value}) used to identify the ZIP archive format.
* @since 1.1
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> */
public static final String ZIP = "zip";
/**
* Constant (value {@value}) used to identify the 7z archive format.
* @since 1.8
*/
public static final String SEVEN_Z = "7z";
/**
* Entry encoding, null for the platform default.
*/
private final String encoding;
/**
* Entry encoding, null for the default.
*/
private volatile String entryEncoding;
private SortedMap<String, ArchiveStreamProvider> archiveInputStreamProviders;
private SortedMap<String, ArchiveStreamProvider> archiveOutputStreamProviders;
private static ArrayList<ArchiveStreamProvider> findArchiveStreamProviders() {
return Lists.newArrayList(serviceLoaderIterator());
}
static void putAll(Set<String> names, ArchiveStreamProvider provider,
TreeMap<String, ArchiveStreamProvider> map) {
for (String name : names) {
map.put(toKey(name), provider);
}
}
private static Iterator<ArchiveStreamProvider> serviceLoaderIterator() {
return new ServiceLoaderIterator<>(ArchiveStreamProvider.class);
}
private static String toKey(final String name) {
return name.toUpperCase(Locale.ROOT);
}
/**
* Constructs a new sorted map from input stream provider names to provider
* objects.
*
* <p>
* The map returned by this method will have one entry for each provider for
* which support is available in the current Java virtual machine. If two or
* more supported provider have the same name then the resulting map will
* contain just one of them; which one it will contain is not specified.
* </p>
*
* <p>
* The invocation of this method, and the subsequent use of the resulting
* map, may cause time-consuming disk or network I/O operations to occur.
* This method is provided for applications that need to enumerate all of
* the available providers, for example to allow user provider selection.
* </p>
*
* <p>
* This method may return different results at different times if new
* providers are dynamically made available to the current Java virtual
* machine.
* </p>
*
* @return An immutable, map from names to provider objects
* @since 1.13
*/
public static SortedMap<String, ArchiveStreamProvider> findAvailableArchiveInputStreamProviders() {
return AccessController.doPrivileged(new PrivilegedAction<SortedMap<String, ArchiveStreamProvider>>() {
@Override
public SortedMap<String, ArchiveStreamProvider> run() {
TreeMap<String, ArchiveStreamProvider> map = new TreeMap<>();
putAll(SINGLETON.getInputStreamArchiveNames(), SINGLETON, map);
for (ArchiveStreamProvider provider : findArchiveStreamProviders()) {
putAll(provider.getInputStreamArchiveNames(), provider, map);
}
return map;
}
});
}
/**
* Constructs a new sorted map from output stream provider names to provider
* objects.
*
* <p>
* The map returned by this method will have one entry for
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> each provider for
* which support is available in the current Java virtual machine. If two or
* more supported provider have the same name then the resulting map will
* contain just one of them; which one it will contain is not specified.
* </p>
*
* <p>
* The invocation of this method, and the subsequent use of the resulting
* map, may cause time-consuming disk or network I/O operations to occur.
* This method is provided for applications that need to enumerate all of
* the available providers, for example to allow user provider selection.
* </p>
*
* <p>
* This method may return different results at different times if new
* providers are dynamically made available to the current Java virtual
* machine.
* </p>
*
* @return An immutable, map from names to provider objects
* @since 1.13
*/
public static SortedMap<String, ArchiveStreamProvider> findAvailableArchiveOutputStreamProviders() {
return AccessController.doPrivileged(new PrivilegedAction<SortedMap<String, ArchiveStreamProvider>>() {
@Override
public SortedMap<String, ArchiveStreamProvider> run() {
TreeMap<String, ArchiveStreamProvider> map = new TreeMap<>();
putAll(SINGLETON.getOutputStreamArchiveNames(), SINGLETON, map);
for (ArchiveStreamProvider provider : findArchiveStreamProviders()) {
putAll(provider.getOutputStreamArchiveNames(), provider, map);
}
return map;
}
});
}
/**
* Create an instance using the platform default encoding.
*/
public ArchiveStreamFactory() {
this(null);
}
/**
* Create an instance using the specified encoding.
*
* @param encoding the encoding to be used.
*
* @since 1.10
*/
public ArchiveStreamFactory(final String encoding) {
super();
this.encoding = encoding;
// Also set the original field so can continue to use it.
this.entryEncoding = encoding;
}
/**
* Returns the encoding to use for arj, jar, zip, dump, cpio and tar
* files, or null for the archiver default.
*
* @return entry encoding, or null for the archiver default
* @since 1.5
*/
public String getEntryEncoding() {
return entryEncoding;
}
/**
* Sets the encoding to use for arj, jar, zip, dump, cpio and tar files. Use null for the archiver default.
*
* @param entryEncoding the entry encoding, null uses the archiver default.
* @since 1.5
* @deprecated 1.10 use {@link #ArchiveStreamFactory(String)} to specify the encoding
* @throws IllegalStateException if the constructor {@link #ArchiveStreamFactory(String)}
* was used to specify the factory encoding.
*/
@Deprecated
public void setEntryEncoding(final String entryEncoding) {
// Note: this does not detect new ArchiveStreamFactory(null) but that does not set the encoding anyway
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
if (encoding != null) {
throw new IllegalStateException("Cannot overide encoding set by the constructor");
}
this.entryEncoding = entryEncoding;
}
/**
* Creates an archive input stream from an archiver name and an input stream.
*
* @param archiverName the archive name,
* i.e. {@value #AR}, {@value #ARJ}, {@value #ZIP}, {@value #TAR}, {@value #JAR}, {@value #CPIO}, {@value #DUMP} or {@value #SEVEN_Z}
* @param in the input stream
* @return the archive input stream
* @throws ArchiveException if the archiver name is not known
* @throws StreamingNotSupportedException if the format cannot be
* read from a stream
* @throws IllegalArgumentException if the archiver name or stream is null
*/
public ArchiveInputStream createArchiveInputStream(final String archiverName, final InputStream in)
throws ArchiveException {
return createArchiveInputStream(archiverName, in, entryEncoding);
}
@Override
public ArchiveInputStream createArchiveInputStream(final String archiverName, final InputStream in,
final String actualEncoding) throws ArchiveException {
if (archiverName == null) {
throw new IllegalArgumentException("Archivername must not be null.");
}
if (in == null) {
throw new IllegalArgumentException("InputStream must not be null.");
}
if (AR.equalsIgnoreCase(archiverName)) {
return new ArArchiveInputStream(in);
}
if (ARJ.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new ArjArchiveInputStream(in, actualEncoding);
}
return new ArjArchiveInputStream(in);
}
if (ZIP.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new ZipArchiveInputStream(in, actualEncoding);
}
return new ZipArchiveInputStream(in);
}
if (TAR.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new TarArchiveInputStream(in, actualEncoding);
}
return new TarArchiveInputStream(in);
}
if (JAR.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new JarArchiveInputStream(in, actualEncoding);
}
return new JarArchiveInputStream(in);
}
if (CPIO.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new CpioArchiveInputStream(in, actualEncoding);
}
return new CpioArchiveInputStream(in);
}
if (DUMP.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new DumpArchiveInputStream(in, actualEncoding);
}
return new DumpArchiveInputStream(in);
}
if (SEVEN_Z.equalsIgnoreCase(archiverName)) {
throw new StreamingNotSupportedException(SEVEN_Z);
}
final ArchiveStreamProvider archiveStreamProvider = getArchiveInputStreamProviders().get(toKey(archiverName));
if (archiveStreamProvider != null) {
return
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> archiveStreamProvider.createArchiveInputStream(archiverName, in, actualEncoding);
}
throw new ArchiveException("Archiver: " + archiverName + " not found.");
}
/**
* Creates an archive output stream from an archiver name and an output stream.
*
* @param archiverName the archive name,
* i.e. {@value #AR}, {@value #ZIP}, {@value #TAR}, {@value #JAR} or {@value #CPIO}
* @param out the output stream
* @return the archive output stream
* @throws ArchiveException if the archiver name is not known
* @throws StreamingNotSupportedException if the format cannot be
* written to a stream
* @throws IllegalArgumentException if the archiver name or stream is null
*/
public ArchiveOutputStream createArchiveOutputStream(final String archiverName, final OutputStream out)
throws ArchiveException {
return createArchiveOutputStream(archiverName, out, entryEncoding);
}
@Override
public ArchiveOutputStream createArchiveOutputStream(
final String archiverName, final OutputStream out, final String actualEncoding)
throws ArchiveException {
if (archiverName == null) {
throw new IllegalArgumentException("Archivername must not be null.");
}
if (out == null) {
throw new IllegalArgumentException("OutputStream must not be null.");
}
if (AR.equalsIgnoreCase(archiverName)) {
return new ArArchiveOutputStream(out);
}
if (ZIP.equalsIgnoreCase(archiverName)) {
final ZipArchiveOutputStream zip = new ZipArchiveOutputStream(out);
if (actualEncoding != null) {
zip.setEncoding(actualEncoding);
}
return zip;
}
if (TAR.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new TarArchiveOutputStream(out, actualEncoding);
}
return new TarArchiveOutputStream(out);
}
if (JAR.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new JarArchiveOutputStream(out, actualEncoding);
}
return new JarArchiveOutputStream(out);
}
if (CPIO.equalsIgnoreCase(archiverName)) {
if (actualEncoding != null) {
return new CpioArchiveOutputStream(out, actualEncoding);
}
return new CpioArchiveOutputStream(out);
}
if (SEVEN_Z.equalsIgnoreCase(archiverName)) {
throw new StreamingNotSupportedException(SEVEN_Z);
}
final ArchiveStreamProvider archiveStreamProvider = getArchiveOutputStreamProviders().get(toKey(archiverName));
if (archiveStreamProvider != null) {
return archiveStreamProvider.createArchiveOutputStream(archiverName, out, actualEncoding);
}
throw new ArchiveException("Archiver: " + archiverName + " not found.");
}
/**
* Create an archive input stream from an input stream, autodetecting
* the archive type from the first few bytes of the stream. The InputStream
* must support marks, like BufferedInputStream.
*
* @param in the input stream
* @return the archive input
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> not use reset and mark operations.", e);
}
throw new ArchiveException("No Archiver found for the stream signature");
}
public SortedMap<String, ArchiveStreamProvider> getArchiveInputStreamProviders() {
if (archiveInputStreamProviders == null) {
archiveInputStreamProviders = Collections
.unmodifiableSortedMap(findAvailableArchiveInputStreamProviders());
}
return archiveInputStreamProviders;
}
public SortedMap<String, ArchiveStreamProvider> getArchiveOutputStreamProviders() {
if (archiveOutputStreamProviders == null) {
archiveOutputStreamProviders = Collections
.unmodifiableSortedMap(findAvailableArchiveOutputStreamProviders());
}
return archiveOutputStreamProviders;
}
@Override
public Set<String> getInputStreamArchiveNames() {
return Sets.newHashSet(AR, ARJ, ZIP, TAR, JAR, CPIO, DUMP, SEVEN_Z);
}
@Override
public Set<String> getOutputStreamArchiveNames() {
return Sets.newHashSet(AR, ZIP, TAR, JAR, CPIO, SEVEN_Z);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> getCentralDirectoryData() {
return getLocalFileDataData();
}
/**
* Populate data from this array as if it was in local file data.
*
* @param data an array of bytes
* @param offset the start offset
* @param length the number of bytes in the array from offset
* @throws java.util.zip.ZipException on error
*/
@Override
public void parseFromLocalFileData(
final byte[] data, int offset, final int length
) throws ZipException {
final int len = offset + length;
// skip reserved
offset += 4;
while (offset + 4 <= len) {
final ZipShort tag = new ZipShort(data, offset);
offset += 2;
if (tag.equals(TIME_ATTR_TAG)) {
readTimeAttr(data, offset, len - offset);
break;
}
final ZipShort size = new ZipShort(data, offset);
offset += 2 + size.getValue();
}
}
/**
* Doesn't do anything special since this class always uses the
* same parsing logic for both central directory and local file data.
*/
@Override
public void parseFromCentralDirectoryData(
final byte[] buffer, final int offset, final int length
) throws ZipException {
reset();
parseFromLocalFileData(buffer, offset, length);
}
/**
* Returns the "File last modification time" of this zip entry as
* a ZipEightByteInteger object, or {@link
* ZipEightByteInteger#ZERO} if no such timestamp exists in the
* zip entry.
*
* @return File last modification time
*/
public ZipEightByteInteger getModifyTime() { return modifyTime; }
/**
* Returns the "File last access time" of this zip entry as a
* ZipEightByteInteger object, or {@link ZipEightByteInteger#ZERO}
* if no such timestamp exists in the zip entry.
*
* @return File last access time
*/
public ZipEightByteInteger getAccessTime() { return accessTime; }
/**
* Returns the "File creation time" of this zip entry as a
* ZipEightByteInteger object, or {@link ZipEightByteInteger#ZERO}
* if no such timestamp exists in the zip entry.
*
* @return File creation time
*/
public ZipEightByteInteger getCreateTime() { return createTime; }
/**
* Returns the modify time as a java.util.Date
* of this zip entry, or null if no such timestamp exists in the zip entry.
*
* @return modify time as java.util.Date or null.
*/
public Date getModifyJavaTime() {
return zipToDate(modifyTime);
}
/**
* Returns the access time as a java.util.Date
* of this zip entry, or null if no such timestamp exists in the zip entry.
*
* @return access time as java.util.Date or null.
*/
public Date getAccessJavaTime
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>() {
return zipToDate(accessTime);
}
/**
* Returns the create time as a a java.util.Date of this zip
* entry, or null if no such timestamp exists in the zip entry.
*
* @return create time as java.util.Date or null.
*/
public Date getCreateJavaTime() {
return zipToDate(createTime);
}
/**
* Sets the File last modification time of this zip entry using a
* ZipEightByteInteger object.
*
* @param t ZipEightByteInteger of the modify time
*/
public void setModifyTime(final ZipEightByteInteger t) {
modifyTime = t == null ? ZipEightByteInteger.ZERO : t;
}
/**
* Sets the File last access time of this zip entry using a
* ZipEightByteInteger object.
*
* @param t ZipEightByteInteger of the access time
*/
public void setAccessTime(final ZipEightByteInteger t) {
accessTime = t == null ? ZipEightByteInteger.ZERO : t;
}
/**
* Sets the File creation time of this zip entry using a
* ZipEightByteInteger object.
*
* @param t ZipEightByteInteger of the create time
*/
public void setCreateTime(final ZipEightByteInteger t) {
createTime = t == null ? ZipEightByteInteger.ZERO : t;
}
/**
* Sets the modify time as a java.util.Date of this zip entry.
*
* @param d modify time as java.util.Date
*/
public void setModifyJavaTime(final Date d) { setModifyTime(dateToZip(d)); }
/**
* Sets the access time as a java.util.Date
* of this zip entry.
*
* @param d access time as java.util.Date
*/
public void setAccessJavaTime(final Date d) { setAccessTime(dateToZip(d)); }
/**
* <p>
* Sets the create time as a java.util.Date
* of this zip entry. Supplied value is truncated to per-second
* precision (milliseconds zeroed-out).
* </p><p>
* Note: the setters for flags and timestamps are decoupled.
* Even if the timestamp is not-null, it will only be written
* out if the corresponding bit in the flags is also set.
* </p>
*
* @param d create time as java.util.Date
*/
public void setCreateJavaTime(final Date d) { setCreateTime(dateToZip(d)); }
/**
* Returns a String representation of this class useful for
* debugging purposes.
*
* @return A String representation of this class useful for
* debugging purposes.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("0x000A Zip Extra Field:")
.append(" Modify:[").
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>pioArchiveInputStream extends ArchiveInputStream implements
CpioConstants {
private boolean closed = false;
private CpioArchiveEntry entry;
private long entryBytesRead = 0;
private boolean entryEOF = false;
private final byte tmpbuf[] = new byte[4096];
private long crc = 0;
private final InputStream in;
// cached buffers - must only be used locally in the class (COMPRESS-172 - reduce garbage collection)
private final byte[] TWO_BYTES_BUF = new byte[2];
private final byte[] FOUR_BYTES_BUF = new byte[4];
private final byte[] SIX_BYTES_BUF = new byte[6];
private final int blockSize;
/**
* The encoding to use for filenames and labels.
*/
private final ZipEncoding zipEncoding;
// the provided encoding (for unit tests)
final String encoding;
/**
* Construct the cpio input stream with a blocksize of {@link
* CpioConstants#BLOCK_SIZE BLOCK_SIZE} and expecting ASCII file
* names.
*
* @param in
* The cpio stream
*/
public CpioArchiveInputStream(final InputStream in) {
this(in, BLOCK_SIZE, CharsetNames.US_ASCII);
}
/**
* Construct the cpio input stream with a blocksize of {@link
* CpioConstants#BLOCK_SIZE BLOCK_SIZE}.
*
* @param in
* The cpio stream
* @param encoding
* The encoding of file names to expect - use null for
* the platform's default.
* @since 1.6
*/
public CpioArchiveInputStream(final InputStream in, final String encoding) {
this(in, BLOCK_SIZE, encoding);
}
/**
* Construct the cpio input stream with a blocksize of {@link
* CpioConstants#BLOCK_SIZE BLOCK_SIZE} expecting ASCII file
* names.
*
* @param in
* The cpio stream
* @param blockSize
* The block size of the archive.
* @since 1.5
*/
public CpioArchiveInputStream(final InputStream in, final int blockSize) {
this(in, blockSize, CharsetNames.US_ASCII);
}
/**
* Construct the cpio input stream with a blocksize of {@link CpioConstants#BLOCK_SIZE BLOCK_SIZE}.
*
* @param in
* The cpio stream
* @param blockSize
* The block size of the archive.
* @param encoding
* The encoding of file names to expect - use null for
* the platform's default.
* @since 1.6
*/
public CpioArchiveInputStream(final InputStream in, final int blockSize, final String encoding) {
this.in = in;
this.blockSize = blockSize;
this.encoding = encoding;
this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
}
/**
* Returns 0 after EOF has reached for the current entry data, otherwise
*
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> always return 1.
* <p>
* Programs should not count on this method to return the actual number of
* bytes that could be read without blocking.
*
* @return 1 before EOF and 0 after EOF has reached for current entry.
* @throws IOException
* if an I/O error has occurred or if a CPIO file error has
* occurred
*/
@Override
public int available() throws IOException {
ensureOpen();
if (this.entryEOF) {
return 0;
}
return 1;
}
/**
* Closes the CPIO input stream.
*
* @throws IOException
* if an I/O error has occurred
*/
@Override
public void close() throws IOException {
if (!this.closed) {
in.close();
this.closed = true;
}
}
/**
* Closes the current CPIO entry and positions the stream for reading the
* next entry.
*
* @throws IOException
* if an I/O error has occurred or if a CPIO file error has
* occurred
*/
private void closeEntry() throws IOException {
// the skip implementation of this class will not skip more
// than Integer.MAX_VALUE bytes
while (skip((long) Integer.MAX_VALUE) == Integer.MAX_VALUE) { // NOPMD
// do nothing
}
}
/**
* Check to make sure that this stream has not been closed
*
* @throws IOException
* if the stream is already closed
*/
private void ensureOpen() throws IOException {
if (this.closed) {
throw new IOException("Stream closed");
}
}
/**
* Reads the next CPIO file entry and positions stream at the beginning of
* the entry data.
*
* @return the CPIOArchiveEntry just read
* @throws IOException
* if an I/O error has occurred or if a CPIO file error has
* occurred
*/
public CpioArchiveEntry getNextCPIOEntry() throws IOException {
ensureOpen();
if (this.entry != null) {
closeEntry();
}
readFully(TWO_BYTES_BUF, 0, TWO_BYTES_BUF.length);
if (CpioUtil.byteArray2long(TWO_BYTES_BUF, false) == MAGIC_OLD_BINARY) {
this.entry = readOldBinaryEntry(false);
} else if (CpioUtil.byteArray2long(TWO_BYTES_BUF, true)
== MAGIC_OLD_BINARY) {
this.entry = readOldBinaryEntry(true);
} else {
System.arraycopy(TWO_BYTES_BUF, 0, SIX_BYTES_BUF, 0,
TWO_BYTES_BUF.length);
readFully(SIX_BYTES_BUF, TWO_BYTES_BUF.length,
FOUR_BYTES_BUF.length);
final String magicString = ArchiveUtils.toAsciiString(SIX_BYTES_BUF);
switch (magicString) {
case MAG
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> return tmpread;
}
private final int readFully(final byte[] b, final int off, final int len)
throws IOException {
final int count = IOUtils.readFully(in, b, off, len);
count(count);
if (count < len) {
throw new EOFException();
}
return count;
}
private long readBinaryLong(final int length, final boolean swapHalfWord)
throws IOException {
final byte tmp[] = new byte[length];
readFully(tmp, 0, tmp.length);
return CpioUtil.byteArray2long(tmp, swapHalfWord);
}
private long readAsciiLong(final int length, final int radix)
throws IOException {
final byte tmpBuffer[] = new byte[length];
readFully(tmpBuffer, 0, tmpBuffer.length);
return Long.parseLong(ArchiveUtils.toAsciiString(tmpBuffer), radix);
}
private CpioArchiveEntry readNewEntry(final boolean hasCrc)
throws IOException {
CpioArchiveEntry ret;
if (hasCrc) {
ret = new CpioArchiveEntry(FORMAT_NEW_CRC);
} else {
ret = new CpioArchiveEntry(FORMAT_NEW);
}
ret.setInode(readAsciiLong(8, 16));
final long mode = readAsciiLong(8, 16);
if (CpioUtil.fileType(mode) != 0){ // mode is initialised to 0
ret.setMode(mode);
}
ret.setUID(readAsciiLong(8, 16));
ret.setGID(readAsciiLong(8, 16));
ret.setNumberOfLinks(readAsciiLong(8, 16));
ret.setTime(readAsciiLong(8, 16));
ret.setSize(readAsciiLong(8, 16));
ret.setDeviceMaj(readAsciiLong(8, 16));
ret.setDeviceMin(readAsciiLong(8, 16));
ret.setRemoteDeviceMaj(readAsciiLong(8, 16));
ret.setRemoteDeviceMin(readAsciiLong(8, 16));
final long namesize = readAsciiLong(8, 16);
ret.setChksum(readAsciiLong(8, 16));
final String name = readCString((int) namesize);
ret.setName(name);
if (CpioUtil.fileType(mode) == 0 && !name.equals(CPIO_TRAILER)){
throw new IOException("Mode 0 only allowed in the trailer. Found entry name: "
+ ArchiveUtils.sanitize(name)
+ " Occured at byte: " + getBytesRead());
}
skip(ret.getHeaderPadCount());
return ret;
}
private CpioArchiveEntry readOldAsciiEntry() throws IOException {
final CpioArchiveEntry ret = new CpioArchiveEntry(FORMAT_OLD_ASCII);
ret.setDevice
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>(readAsciiLong(6, 8));
ret.setInode(readAsciiLong(6, 8));
final long mode = readAsciiLong(6, 8);
if (CpioUtil.fileType(mode) != 0) {
ret.setMode(mode);
}
ret.setUID(readAsciiLong(6, 8));
ret.setGID(readAsciiLong(6, 8));
ret.setNumberOfLinks(readAsciiLong(6, 8));
ret.setRemoteDevice(readAsciiLong(6, 8));
ret.setTime(readAsciiLong(11, 8));
final long namesize = readAsciiLong(6, 8);
ret.setSize(readAsciiLong(11, 8));
final String name = readCString((int) namesize);
ret.setName(name);
if (CpioUtil.fileType(mode) == 0 && !name.equals(CPIO_TRAILER)){
throw new IOException("Mode 0 only allowed in the trailer. Found entry: "
+ ArchiveUtils.sanitize(name)
+ " Occured at byte: " + getBytesRead());
}
return ret;
}
private CpioArchiveEntry readOldBinaryEntry(final boolean swapHalfWord)
throws IOException {
final CpioArchiveEntry ret = new CpioArchiveEntry(FORMAT_OLD_BINARY);
ret.setDevice(readBinaryLong(2, swapHalfWord));
ret.setInode(readBinaryLong(2, swapHalfWord));
final long mode = readBinaryLong(2, swapHalfWord);
if (CpioUtil.fileType(mode) != 0){
ret.setMode(mode);
}
ret.setUID(readBinaryLong(2, swapHalfWord));
ret.setGID(readBinaryLong(2, swapHalfWord));
ret.setNumberOfLinks(readBinaryLong(2, swapHalfWord));
ret.setRemoteDevice(readBinaryLong(2, swapHalfWord));
ret.setTime(readBinaryLong(4, swapHalfWord));
final long namesize = readBinaryLong(2, swapHalfWord);
ret.setSize(readBinaryLong(4, swapHalfWord));
final String name = readCString((int) namesize);
ret.setName(name);
if (CpioUtil.fileType(mode) == 0 && !name.equals(CPIO_TRAILER)){
throw new IOException("Mode 0 only allowed in the trailer. Found entry: "
+ ArchiveUtils.sanitize(name)
+ "Occured at byte: " + getBytesRead());
}
skip(ret.getHeaderPadCount());
return ret;
}
private String readCString(final int length) throws IOException {
// don't include trailing NUL in file name to decode
final byte tmpBuffer[] = new byte[length - 1];
readFully(tmpBuffer, 0, tmpBuffer.length);
this.in.read();
return
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> component.</p>
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @since 1.4
* @version $Id$
*/
public class Charsets {
//
// This class should only contain Charset instances for required encodings. This guarantees that it will load correctly and
// without delay on all Java platforms.
//
/**
* Returns the given Charset or the default Charset if the given Charset is null.
*
* @param charset
* A charset or null.
* @return the given Charset or the default Charset if the given Charset is null
*/
public static Charset toCharset(final Charset charset) {
return charset == null ? Charset.defaultCharset() : charset;
}
/**
* Returns a Charset for the named charset. If the name is null, return the default Charset.
*
* @param charset
* The name of the requested charset, may be null.
* @return a Charset for the named charset
* @throws java.nio.charset.UnsupportedCharsetException
* If the named charset is unavailable
* @throws java.nio.charset.IllegalCharsetNameException
* If the given charset name is illegal
*/
public static Charset toCharset(final String charset) {
return charset == null ? Charset.defaultCharset() : Charset.forName(charset);
}
/**
* CharsetNamesISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final Charset ISO_8859_1 = Charset.forName(CharsetNames.ISO_8859_1);
/**
* <p>
* Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
* </p>
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final Charset US_ASCII = Charset.forName(CharsetNames.US_ASCII);
/**
* <p>
* Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
* (either order accepted on input, big-endian used on output)
* </p>
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> an I/O error occurs
*/
public abstract void closeArchiveEntry() throws IOException;
/**
* Finishes the addition of entries to this stream, without closing it.
* Additional data can be written, if the format supports it.
*
* @throws IOException if the user forgets to close the entry.
*/
public abstract void finish() throws IOException;
/**
* Create an archive entry using the inputFile and entryName provided.
*
* @param inputFile the file to create the entry from
* @param entryName name to use for the entry
* @return the ArchiveEntry set up with details from the file
*
* @throws IOException if an I/O error occurs
*/
public abstract ArchiveEntry createArchiveEntry(File inputFile, String entryName) throws IOException;
// Generic implementations of OutputStream methods that may be useful to sub-classes
/**
* Writes a byte to the current archive entry.
*
* <p>This method simply calls {@code write( byte[], 0, 1 )}.
*
* <p>MUST be overridden if the {@link #write(byte[], int, int)} method
* is not overridden; may be overridden otherwise.
*
* @param b The byte to be written.
* @throws IOException on error
*/
@Override
public void write(final int b) throws IOException {
oneByte[0] = (byte) (b & BYTE_MASK);
write(oneByte, 0, 1);
}
/**
* Increments the counter of already written bytes.
* Doesn't increment if EOF has been hit ({@code written == -1}).
*
* @param written the number of bytes written
*/
protected void count(final int written) {
count((long) written);
}
/**
* Increments the counter of already written bytes.
* Doesn't increment if EOF has been hit ({@code written == -1}).
*
* @param written the number of bytes written
* @since 1.1
*/
protected void count(final long written) {
if (written != -1) {
bytesWritten = bytesWritten + written;
}
}
/**
* Returns the current number of bytes written to this stream.
* @return the number of written bytes
* @deprecated this method may yield wrong results for large
* archives, use #getBytesWritten instead
*/
@Deprecated
public int getCount() {
return (int) bytesWritten;
}
/**
* Returns the current number of bytes written to this stream.
* @return the number of written bytes
* @since 1.1
*/
public long getBytesWritten() {
return bytesWritten;
}
/**
* Whether this stream is able to write the given entry.
*
* <p>Some archive formats support variants or details that are
* not supported (yet).</p>
*
* @param archiveEntry
* the entry to test
* @return This implementation always returns true.
* @since 1.1
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.jar;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.JarMarker;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
/**
* Subclass that adds a special extra field to the very first entry
* which allows the created archive to be used as an executable jar on
* Solaris.
*
* @NotThreadSafe
*/
public class JarArchiveOutputStream extends ZipArchiveOutputStream {
private boolean jarMarkerAdded = false;
public JarArchiveOutputStream(final OutputStream out) {
super(out);
}
/**
* Create and instance that wraps the output stream using the provided encoding.
*
* @param out the output stream to wrap
* @param encoding the encoding to use. Use null for the platform default.
* @since 1.10
*/
public JarArchiveOutputStream(final OutputStream out, final String encoding) {
super(out);
setEncoding(encoding);
}
// @throws ClassCastException if entry is not an instance of ZipArchiveEntry
@Override
public void putArchiveEntry(final ArchiveEntry ze) throws IOException {
if (!jarMarkerAdded) {
((ZipArchiveEntry)ze).addAsFirstExtraField(JarMarker.getInstance());
jarMarkerAdded = true;
}
super.putArchiveEntry(ze);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
/**
* The encoding to use for filenames and labels.
*/
private final ZipEncoding zipEncoding;
// the provided encoding (for unit tests)
final String encoding;
/**
* Constructor using the platform's default encoding for file
* names.
*
* @param is stream to read from
* @throws ArchiveException on error
*/
public DumpArchiveInputStream(final InputStream is) throws ArchiveException {
this(is, null);
}
/**
* Constructor.
*
* @param is stream to read from
* @param encoding the encoding to use for file names, use null
* for the platform's default encoding
* @since 1.6
* @throws ArchiveException on error
*/
public DumpArchiveInputStream(final InputStream is, final String encoding)
throws ArchiveException {
this.raw = new TapeInputStream(is);
this.hasHitEOF = false;
this.encoding = encoding;
this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
try {
// read header, verify it's a dump archive.
final byte[] headerBytes = raw.readRecord();
if (!DumpArchiveUtil.verify(headerBytes)) {
throw new UnrecognizedFormatException();
}
// get summary information
summary = new DumpArchiveSummary(headerBytes, this.zipEncoding);
// reset buffer with actual block size.
raw.resetBlockSize(summary.getNTRec(), summary.isCompressed());
// allocate our read buffer.
blockBuffer = new byte[4 * DumpArchiveConstants.TP_SIZE];
// skip past CLRI and BITS segments since we don't handle them yet.
readCLRI();
readBITS();
} catch (final IOException ex) {
throw new ArchiveException(ex.getMessage(), ex);
}
// put in a dummy record for the root node.
final Dirent root = new Dirent(2, 2, 4, ".");
names.put(2, root);
// use priority based on queue to ensure parent directories are
// released first.
queue = new PriorityQueue<>(10,
new Comparator<DumpArchiveEntry>() {
@Override
public int compare(final DumpArchiveEntry p, final DumpArchiveEntry q) {
if (p.getOriginalName() == null || q.getOriginalName() == null) {
return Integer.MAX_VALUE;
}
return p.getOriginalName().compareTo(q.getOriginalName());
}
});
}
@Deprecated
@Override
public int getCount() {
return (int) getBytesRead();
}
@Override
public long getBytesRead() {
return raw.getBytesRead();
}
/**
* Return the archive summary information.
* @return the summary
*/
public DumpArchiveSummary getSummary() {
return summary;
}
/**
* Read CLRI (deleted inode) segment.
*/
private void readCLRI() throws IOException {
final byte[] buffer = raw.readRecord();
if (!DumpArchiveUtil.verify(buffer)) {
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
throw new InvalidFormatException();
}
active = DumpArchiveEntry.parse(buffer);
if (DumpArchiveConstants.SEGMENT_TYPE.CLRI != active.getHeaderType()) {
throw new InvalidFormatException();
}
// we don't do anything with this yet.
if (raw.skip(DumpArchiveConstants.TP_SIZE * active.getHeaderCount())
== -1) {
throw new EOFException();
}
readIdx = active.getHeaderCount();
}
/**
* Read BITS segment.
*/
private void readBITS() throws IOException {
final byte[] buffer = raw.readRecord();
if (!DumpArchiveUtil.verify(buffer)) {
throw new InvalidFormatException();
}
active = DumpArchiveEntry.parse(buffer);
if (DumpArchiveConstants.SEGMENT_TYPE.BITS != active.getHeaderType()) {
throw new InvalidFormatException();
}
// we don't do anything with this yet.
if (raw.skip(DumpArchiveConstants.TP_SIZE * active.getHeaderCount())
== -1) {
throw new EOFException();
}
readIdx = active.getHeaderCount();
}
/**
* Read the next entry.
* @return the next entry
* @throws IOException on error
*/
public DumpArchiveEntry getNextDumpEntry() throws IOException {
return getNextEntry();
}
@Override
public DumpArchiveEntry getNextEntry() throws IOException {
DumpArchiveEntry entry = null;
String path = null;
// is there anything in the queue?
if (!queue.isEmpty()) {
return queue.remove();
}
while (entry == null) {
if (hasHitEOF) {
return null;
}
// skip any remaining records in this segment for prior file.
// we might still have holes... easiest to do it
// block by block. We may want to revisit this if
// the unnecessary decompression time adds up.
while (readIdx < active.getHeaderCount()) {
if (!active.isSparseRecord(readIdx++)
&& raw.skip(DumpArchiveConstants.TP_SIZE) == -1) {
throw new EOFException();
}
}
readIdx = 0;
filepos = raw.getBytesRead();
byte[] headerBytes = raw.readRecord();
if (!DumpArchiveUtil.verify(headerBytes)) {
throw new InvalidFormatException();
}
active = DumpArchiveEntry.parse(headerBytes);
// skip any remaining segments for prior file.
while (DumpArchiveConstants.SEGMENT_TYPE.ADDR == active.getHeaderType()) {
if (raw.skip(DumpArchiveConstants.TP_SIZE
* (active.getHeaderCount()
- active.getHeaderHoles())) == -1) {
throw new EOFException();
}
filepos = raw.getBytesRead();
headerBytes = raw.readRecord();
if (!DumpArchiveUtil.verify(headerBytes)) {
throw new InvalidFormatException();
}
active = DumpArchiveEntry.parse(headerBytes);
}
// check if this is an end-of-volume marker.
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> if (DumpArchiveConstants.SEGMENT_TYPE.END == active.getHeaderType()) {
hasHitEOF = true;
return null;
}
entry = active;
if (entry.isDirectory()) {
readDirectoryEntry(active);
// now we create an empty InputStream.
entryOffset = 0;
entrySize = 0;
readIdx = active.getHeaderCount();
} else {
entryOffset = 0;
entrySize = active.getEntrySize();
readIdx = 0;
}
recordOffset = readBuf.length;
path = getPath(entry);
if (path == null) {
entry = null;
}
}
entry.setName(path);
entry.setSimpleName(names.get(entry.getIno()).getName());
entry.setOffset(filepos);
return entry;
}
/**
* Read directory entry.
*/
private void readDirectoryEntry(DumpArchiveEntry entry)
throws IOException {
long size = entry.getEntrySize();
boolean first = true;
while (first ||
DumpArchiveConstants.SEGMENT_TYPE.ADDR == entry.getHeaderType()) {
// read the header that we just peeked at.
if (!first) {
raw.readRecord();
}
if (!names.containsKey(entry.getIno()) &&
DumpArchiveConstants.SEGMENT_TYPE.INODE == entry.getHeaderType()) {
pending.put(entry.getIno(), entry);
}
final int datalen = DumpArchiveConstants.TP_SIZE * entry.getHeaderCount();
if (blockBuffer.length < datalen) {
blockBuffer = new byte[datalen];
}
if (raw.read(blockBuffer, 0, datalen) != datalen) {
throw new EOFException();
}
int reclen = 0;
for (int i = 0; i < datalen - 8 && i < size - 8;
i += reclen) {
final int ino = DumpArchiveUtil.convert32(blockBuffer, i);
reclen = DumpArchiveUtil.convert16(blockBuffer, i + 4);
final byte type = blockBuffer[i + 6];
final String name = DumpArchiveUtil.decode(zipEncoding, blockBuffer, i + 8, blockBuffer[i + 7]);
if (".".equals(name) || "..".equals(name)) {
// do nothing...
continue;
}
final Dirent d = new Dirent(ino, entry.getIno(), type, name);
/*
if ((type == 4) && names.containsKey(ino)) {
System.out.println("we already have ino: " +
names.get(ino));
}
*/
names.put(ino, d);
// check whether this allows us to fill anything in the pending list.
for (final Map.Entry<Integer, DumpArchiveEntry> e : pending.entrySet()) {
final String path = getPath(e.getValue());
if (path
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> != null) {
e.getValue().setName(path);
e.getValue()
.setSimpleName(names.get(e.getKey()).getName());
queue.add(e.getValue());
}
}
// remove anything that we found. (We can't do it earlier
// because of concurrent modification exceptions.)
for (final DumpArchiveEntry e : queue) {
pending.remove(e.getIno());
}
}
final byte[] peekBytes = raw.peek();
if (!DumpArchiveUtil.verify(peekBytes)) {
throw new InvalidFormatException();
}
entry = DumpArchiveEntry.parse(peekBytes);
first = false;
size -= DumpArchiveConstants.TP_SIZE;
}
}
/**
* Get full path for specified archive entry, or null if there's a gap.
*
* @param entry
* @return full path for specified archive entry, or null if there's a gap.
*/
private String getPath(final DumpArchiveEntry entry) {
// build the stack of elements. It's possible that we're
// still missing an intermediate value and if so we
final Stack<String> elements = new Stack<>();
Dirent dirent = null;
for (int i = entry.getIno();; i = dirent.getParentIno()) {
if (!names.containsKey(i)) {
elements.clear();
break;
}
dirent = names.get(i);
elements.push(dirent.getName());
if (dirent.getIno() == dirent.getParentIno()) {
break;
}
}
// if an element is missing defer the work and read next entry.
if (elements.isEmpty()) {
pending.put(entry.getIno(), entry);
return null;
}
// generate full path from stack of elements.
final StringBuilder sb = new StringBuilder(elements.pop());
while (!elements.isEmpty()) {
sb.append('/');
sb.append(elements.pop());
}
return sb.toString();
}
/**
* Reads bytes from the current dump archive entry.
*
* This method is aware of the boundaries of the current
* entry in the archive and will deal with them as if they
* were this stream's start and EOF.
*
* @param buf The buffer into which to place bytes read.
* @param off The offset at which to place bytes read.
* @param len The number of bytes to read.
* @return The number of bytes read, or -1 at EOF.
* @throws IOException on error
*/
@Override
public int read(final byte[] buf, int off, int len) throws IOException {
int totalRead = 0;
if (hasHitEOF || isClosed || entryOffset >= entrySize) {
return -1;
}
if (active == null) {
throw new IllegalStateException("No current dump entry");
}
if (len + entryOffset > entrySize) {
len = (int) (entrySize - entryOffset);
}
while
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers;
import java.util.Date;
/**
* Represents an entry of an archive.
*/
public interface ArchiveEntry {
/**
* Gets the name of the entry in this archive. May refer to a file or directory or other item.
*
* @return The name of this entry in the archive.
*/
String getName();
/**
* Gets the uncompressed size of this entry. May be -1 (SIZE_UNKNOWN) if the size is unknown
*
* @return the uncompressed size of this entry.
*/
long getSize();
/** Special value indicating that the size is unknown */
long SIZE_UNKNOWN = -1;
/**
* Returns true if this entry refers to a directory.
*
* @return true if this entry refers to a directory.
*/
boolean isDirectory();
/**
* Gets the last modified date of this entry.
*
* @return the last modified date of this entry.
* @since 1.1
*/
Date getLastModifiedDate();
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> 25) & 0x7f) + 1980);
cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1);
cal.set(Calendar.DATE, (int) (dosTime >> 16) & 0x1f);
cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f);
cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f);
cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e);
cal.set(Calendar.MILLISECOND, 0);
// CheckStyle:MagicNumberCheck ON
return cal.getTime().getTime();
}
/**
* If the entry has Unicode*ExtraFields and the CRCs of the
* names/comments match those of the extra fields, transfer the
* known Unicode values from the extra field.
*/
static void setNameAndCommentFromExtraFields(final ZipArchiveEntry ze,
final byte[] originalNameBytes,
final byte[] commentBytes) {
final UnicodePathExtraField name = (UnicodePathExtraField)
ze.getExtraField(UnicodePathExtraField.UPATH_ID);
final String originalName = ze.getName();
final String newName = getUnicodeStringIfOriginalMatches(name,
originalNameBytes);
if (newName != null && !originalName.equals(newName)) {
ze.setName(newName);
}
if (commentBytes != null && commentBytes.length > 0) {
final UnicodeCommentExtraField cmt = (UnicodeCommentExtraField)
ze.getExtraField(UnicodeCommentExtraField.UCOM_ID);
final String newComment =
getUnicodeStringIfOriginalMatches(cmt, commentBytes);
if (newComment != null) {
ze.setComment(newComment);
}
}
}
/**
* If the stored CRC matches the one of the given name, return the
* Unicode name of the given field.
*
* <p>If the field is null or the CRCs don't match, return null
* instead.</p>
*/
private static
String getUnicodeStringIfOriginalMatches(final AbstractUnicodeExtraField f,
final byte[] orig) {
if (f != null) {
final CRC32 crc32 = new CRC32();
crc32.update(orig);
final long origCRC32 = crc32.getValue();
if (origCRC32 == f.getNameCRC32()) {
try {
return ZipEncodingHelper
.UTF8_ZIP_ENCODING.decode(f.getUnicodeName());
} catch (final IOException ex) {
// UTF-8 unsupported? should be impossible the
// Unicode*ExtraField must contain some bad bytes
// TODO log this anywhere?
return null;
}
}
}
return null;
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>1 means that the method has not been specified.
*
* @see <a href="https://issues.apache.org/jira/browse/COMPRESS-93"
* >COMPRESS-93</a>
*/
private int method = ZipMethod.UNKNOWN_CODE;
/**
* The {@link java.util.zip.ZipEntry#setSize} method in the base
* class throws an IllegalArgumentException if the size is bigger
* than 2GB for Java versions < 7. Need to keep our own size
* information for Zip64 support.
*/
private long size = SIZE_UNKNOWN;
private int internalAttributes = 0;
private int versionRequired;
private int versionMadeBy;
private int platform = PLATFORM_FAT;
private int rawFlag;
private long externalAttributes = 0;
private ZipExtraField[] extraFields;
private UnparseableExtraFieldData unparseableExtra = null;
private String name = null;
private byte[] rawName = null;
private GeneralPurposeBit gpb = new GeneralPurposeBit();
private static final ZipExtraField[] noExtraFields = new ZipExtraField[0];
/**
* Creates a new zip entry with the specified name.
*
* <p>Assumes the entry represents a directory if and only if the
* name ends with a forward slash "/".</p>
*
* @param name the name of the entry
*/
public ZipArchiveEntry(final String name) {
super(name);
setName(name);
}
/**
* Creates a new zip entry with fields taken from the specified zip entry.
*
* <p>Assumes the entry represents a directory if and only if the
* name ends with a forward slash "/".</p>
*
* @param entry the entry to get fields from
* @throws ZipException on error
*/
public ZipArchiveEntry(final java.util.zip.ZipEntry entry) throws ZipException {
super(entry);
setName(entry.getName());
final byte[] extra = entry.getExtra();
if (extra != null) {
setExtraFields(ExtraFieldUtils.parse(extra, true,
ExtraFieldUtils
.UnparseableExtraField.READ));
} else {
// initializes extra data to an empty byte array
setExtra();
}
setMethod(entry.getMethod());
this.size = entry.getSize();
}
/**
* Creates a new zip entry with fields taken from the specified zip entry.
*
* <p>Assumes the entry represents a directory if and only if the
* name ends with a forward slash "/".</p>
*
* @param entry the entry to get fields from
* @throws ZipException on error
*/
public ZipArchiveEntry(final ZipArchiveEntry entry) throws ZipException {
this((java.util.zip.ZipEntry) entry);
setInternalAttributes(entry.getInternalAttributes());
setExternalAttributes(entry.getExternalAttributes());
setExtraFields(getAllExtraFieldsNoCopy());
setPlatform(entry.get
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>Platform());
final GeneralPurposeBit other = entry.getGeneralPurposeBit();
setGeneralPurposeBit(other == null ? null :
(GeneralPurposeBit) other.clone());
}
/**
*/
protected ZipArchiveEntry() {
this("");
}
/**
* Creates a new zip entry taking some information from the given
* file and using the provided name.
*
* <p>The name will be adjusted to end with a forward slash "/" if
* the file is a directory. If the file is not a directory a
* potential trailing forward slash will be stripped from the
* entry name.</p>
* @param inputFile file to create the entry from
* @param entryName name of the entry
*/
public ZipArchiveEntry(final File inputFile, final String entryName) {
this(inputFile.isDirectory() && !entryName.endsWith("/") ?
entryName + "/" : entryName);
if (inputFile.isFile()){
setSize(inputFile.length());
}
setTime(inputFile.lastModified());
// TODO are there any other fields we can set here?
}
/**
* Overwrite clone.
* @return a cloned copy of this ZipArchiveEntry
*/
@Override
public Object clone() {
final ZipArchiveEntry e = (ZipArchiveEntry) super.clone();
e.setInternalAttributes(getInternalAttributes());
e.setExternalAttributes(getExternalAttributes());
e.setExtraFields(getAllExtraFieldsNoCopy());
return e;
}
/**
* Returns the compression method of this entry, or -1 if the
* compression method has not been specified.
*
* @return compression method
*
* @since 1.1
*/
@Override
public int getMethod() {
return method;
}
/**
* Sets the compression method of this entry.
*
* @param method compression method
*
* @since 1.1
*/
@Override
public void setMethod(final int method) {
if (method < 0) {
throw new IllegalArgumentException(
"ZIP compression method can not be negative: " + method);
}
this.method = method;
}
/**
* Retrieves the internal file attributes.
*
* <p><b>Note</b>: {@link ZipArchiveInputStream} is unable to fill
* this field, you must use {@link ZipFile} if you want to read
* entries using this attribute.</p>
*
* @return the internal file attributes
*/
public int getInternalAttributes() {
return internalAttributes;
}
/**
* Sets the internal file attributes.
* @param value an <code>int</code> value
*/
public void setInternalAttributes(final int value) {
internalAttributes = value;
}
/**
* Retrieves the external file attributes.
*
* <p><b>Note</b>: {@link ZipArchiveInputStream} is unable to fill
* this field, you must use {@link ZipFile} if you want to read
* entries using this attribute.</p>
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> such field exists.
*/
public ZipExtraField getExtraField(final ZipShort type) {
if (extraFields != null) {
for (final ZipExtraField extraField : extraFields) {
if (type.equals(extraField.getHeaderId())) {
return extraField;
}
}
}
return null;
}
/**
* Looks up extra field data that couldn't be parsed correctly.
*
* @return null if no such field exists.
*
* @since 1.1
*/
public UnparseableExtraFieldData getUnparseableExtraFieldData() {
return unparseableExtra;
}
/**
* Parses the given bytes as extra field data and consumes any
* unparseable data as an {@link UnparseableExtraFieldData}
* instance.
* @param extra an array of bytes to be parsed into extra fields
* @throws RuntimeException if the bytes cannot be parsed
* @throws RuntimeException on error
*/
@Override
public void setExtra(final byte[] extra) throws RuntimeException {
try {
final ZipExtraField[] local =
ExtraFieldUtils.parse(extra, true,
ExtraFieldUtils.UnparseableExtraField.READ);
mergeExtraFields(local, true);
} catch (final ZipException e) {
// actually this is not possible as of Commons Compress 1.1
throw new RuntimeException("Error parsing extra fields for entry: "
+ getName() + " - " + e.getMessage(), e);
}
}
/**
* Unfortunately {@link java.util.zip.ZipOutputStream
* java.util.zip.ZipOutputStream} seems to access the extra data
* directly, so overriding getExtra doesn't help - we need to
* modify super's data directly.
*/
protected void setExtra() {
super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getAllExtraFieldsNoCopy()));
}
/**
* Sets the central directory part of extra fields.
* @param b an array of bytes to be parsed into extra fields
*/
public void setCentralDirectoryExtra(final byte[] b) {
try {
final ZipExtraField[] central =
ExtraFieldUtils.parse(b, false,
ExtraFieldUtils.UnparseableExtraField.READ);
mergeExtraFields(central, false);
} catch (final ZipException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* Retrieves the extra data for the local file data.
* @return the extra data for local file
*/
public byte[] getLocalFileDataExtra() {
final byte[] extra = getExtra();
return extra != null ? extra : EMPTY;
}
/**
* Retrieves the extra data for the central directory.
* @return the central directory extra data
*/
public byte[] getCentralDirectoryExtra() {
return ExtraFieldUtils.mergeCentralDirectoryData(getAllExtraFieldsNoCopy());
}
/**
* Get the name of the entry.
* @return the entry name
*/
@Override
public
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> String getName() {
return name == null ? super.getName() : name;
}
/**
* Is this entry a directory?
* @return true if the entry is a directory
*/
@Override
public boolean isDirectory() {
return getName().endsWith("/");
}
/**
* Set the name of the entry.
* @param name the name to use
*/
protected void setName(String name) {
if (name != null && getPlatform() == PLATFORM_FAT
&& !name.contains("/")) {
name = name.replace('\\', '/');
}
this.name = name;
}
/**
* Gets the uncompressed size of the entry data.
*
* <p><b>Note</b>: {@link ZipArchiveInputStream} may create
* entries that return {@link #SIZE_UNKNOWN SIZE_UNKNOWN} as long
* as the entry hasn't been read completely.</p>
*
* @return the entry size
*/
@Override
public long getSize() {
return size;
}
/**
* Sets the uncompressed size of the entry data.
* @param size the uncompressed size in bytes
* @throws IllegalArgumentException if the specified size is less
* than 0
*/
@Override
public void setSize(final long size) {
if (size < 0) {
throw new IllegalArgumentException("invalid entry size");
}
this.size = size;
}
/**
* Sets the name using the raw bytes and the string created from
* it by guessing or using the configured encoding.
* @param name the name to use created from the raw bytes using
* the guessed or configured encoding
* @param rawName the bytes originally read as name from the
* archive
* @since 1.2
*/
protected void setName(final String name, final byte[] rawName) {
setName(name);
this.rawName = rawName;
}
/**
* Returns the raw bytes that made up the name before it has been
* converted using the configured or guessed encoding.
*
* <p>This method will return null if this instance has not been
* read from an archive.</p>
*
* @return the raw name bytes
* @since 1.2
*/
public byte[] getRawName() {
if (rawName != null) {
final byte[] b = new byte[rawName.length];
System.arraycopy(rawName, 0, b, 0, rawName.length);
return b;
}
return null;
}
/**
* Get the hashCode of the entry.
* This uses the name as the hashcode.
* @return a hashcode.
*/
@Override
public int hashCode() {
// this method has severe consequences on performance. We cannot rely
// on the super.hashCode() method since super.getName() always return
// the empty string in the current implemention (there's no setter)
// so it is basically draining the performance of a hashmap lookup
return
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> getName().hashCode();
}
/**
* The "general purpose bit" field.
* @return the general purpose bit
* @since 1.1
*/
public GeneralPurposeBit getGeneralPurposeBit() {
return gpb;
}
/**
* The "general purpose bit" field.
* @param b the general purpose bit
* @since 1.1
*/
public void setGeneralPurposeBit(final GeneralPurposeBit b) {
gpb = b;
}
/**
* If there are no extra fields, use the given fields as new extra
* data - otherwise merge the fields assuming the existing fields
* and the new fields stem from different locations inside the
* archive.
* @param f the extra fields to merge
* @param local whether the new fields originate from local data
*/
private void mergeExtraFields(final ZipExtraField[] f, final boolean local)
throws ZipException {
if (extraFields == null) {
setExtraFields(f);
} else {
for (final ZipExtraField element : f) {
ZipExtraField existing;
if (element instanceof UnparseableExtraFieldData) {
existing = unparseableExtra;
} else {
existing = getExtraField(element.getHeaderId());
}
if (existing == null) {
addExtraField(element);
} else {
if (local) {
final byte[] b = element.getLocalFileDataData();
existing.parseFromLocalFileData(b, 0, b.length);
} else {
final byte[] b = element.getCentralDirectoryData();
existing.parseFromCentralDirectoryData(b, 0, b.length);
}
}
}
setExtra();
}
}
/**
* Wraps {@link java.util.zip.ZipEntry#getTime} with a {@link Date} as the
* entry's last modified date.
*
* <p>Changes to the implementation of {@link java.util.zip.ZipEntry#getTime}
* leak through and the returned value may depend on your local
* time zone as well as your version of Java.</p>
*/
@Override
public Date getLastModifiedDate() {
return new Date(getTime());
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final ZipArchiveEntry other = (ZipArchiveEntry) obj;
final String myName = getName();
final String otherName = other.getName();
if (myName == null) {
if (otherName != null) {
return false;
}
} else if (!myName.equals(otherName)) {
return false;
}
String myComment = getComment();
String otherComment = other.getComment();
if (myComment == null)
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.commons.compress.archivers.zip;
import java.util.zip.ZipException;
/**
* Exception thrown when attempting to read or write data for a zip
* entry that uses ZIP features not supported by this library.
* @since 1.1
*/
public class UnsupportedZipFeatureException extends ZipException {
private final Feature reason;
private final ZipArchiveEntry entry;
private static final long serialVersionUID = 20130101L;
/**
* Creates an exception.
* @param reason the feature that is not supported
* @param entry the entry using the feature
*/
public UnsupportedZipFeatureException(final Feature reason,
final ZipArchiveEntry entry) {
super("unsupported feature " + reason + " used in entry "
+ entry.getName());
this.reason = reason;
this.entry = entry;
}
/**
* Creates an exception for archives that use an unsupported
* compression algorithm.
* @param method the method that is not supported
* @param entry the entry using the feature
* @since 1.5
*/
public UnsupportedZipFeatureException(final ZipMethod method,
final ZipArchiveEntry entry) {
super("unsupported feature method '" + method.name()
+ "' used in entry " + entry.getName());
this.reason = Feature.METHOD;
this.entry = entry;
}
/**
* Creates an exception when the whole archive uses an unsupported
* feature.
*
* @param reason the feature that is not supported
* @since 1.5
*/
public UnsupportedZipFeatureException(final Feature reason) {
super("unsupported feature " + reason + " used in archive.");
this.reason = reason;
this.entry = null;
}
/**
* The unsupported feature that has been used.
* @return The unsupported feature that has been used.
*/
public Feature getFeature() {
return reason;
}
/**
* The entry using the unsupported feature.
* @return The entry using the unsupported feature.
*/
public ZipArchiveEntry getEntry() {
return entry;
}
/**
* ZIP Features that
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> may or may not be supported.
* @since 1.1
*/
public static class Feature {
/**
* The entry is encrypted.
*/
public static final Feature ENCRYPTION = new Feature("encryption");
/**
* The entry used an unsupported compression method.
*/
public static final Feature METHOD = new Feature("compression method");
/**
* The entry uses a data descriptor.
*/
public static final Feature DATA_DESCRIPTOR = new Feature("data descriptor");
/**
* The archive uses splitting or spanning.
* @since 1.5
*/
public static final Feature SPLITTING = new Feature("splitting");
private final String name;
private Feature(final String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.zip;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* A fallback ZipEncoding, which uses a java.io means to encode names.
*
* <p>This implementation is not suitable for encodings other than
* UTF-8, because java.io encodes unmappable character as question
* marks leading to unreadable ZIP entries on some operating
* systems.</p>
*
* <p>Furthermore this implementation is unable to tell whether a
* given name can be safely encoded or not.</p>
*
* <p>This implementation acts as a last resort implementation, when
* neither {@link Simple8BitZipEnoding} nor {@link NioZipEncoding} is
* available.</p>
*
* <p>The methods of this class are reentrant.</p>
* @Immutable
*/
class FallbackZipEncoding implements ZipEncoding {
private final String charsetName;
/**
* Construct a fallback zip encoding, which uses the platform's
* default charset.
*/
public FallbackZipEncoding() {
this.charsetName = null;
}
/**
* Construct a fallback zip encoding, which uses the given charset.
*
* @param charsetName The name of the charset or {@code null} for
* the platform's default character set.
*/
public FallbackZipEncoding(final String charsetName) {
this.charsetName = charsetName;
}
/**
* @see
* org.apache.commons.compress.archivers.zip.ZipEncoding#canEncode(java.lang.String)
*/
@Override
public boolean canEncode(final String name) {
return true;
}
/**
* @see
* org.apache.commons.compress.archivers.zip.ZipEncoding#encode(java.lang.String)
*/
@Override
public ByteBuffer encode(final String name) throws IOException {
if (this.charsetName == null) { // i.e. use default charset, see no-args constructor
return ByteBuffer.wrap(name.getBytes());
}
return ByteBuffer.wrap(name.getBytes(this.
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>charsetName));
}
/**
* @see
* org.apache.commons.compress.archivers.zip.ZipEncoding#decode(byte[])
*/
@Override
public String decode(final byte[] data) throws IOException {
if (this.charsetName == null) { // i.e. use default charset, see no-args constructor
return new String(data);
}
return new String(data,this.charsetName);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>[] getBytes(final int value) {
final byte[] result = new byte[2];
putShort(value, result, 0);
return result;
}
/**
* put the value as two bytes in big endian byte order.
* @param value the Java int to convert to bytes
* @param buf the output buffer
* @param offset
* The offset within the output buffer of the first byte to be written.
* must be non-negative and no larger than <tt>buf.length-2</tt>
*/
public static void putShort(final int value, final byte[] buf, final int offset) {
buf[offset] = (byte) (value & BYTE_MASK);
buf[offset+1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
}
/**
* Helper method to get the value as a java int from two bytes starting at given array offset
* @param bytes the array of bytes
* @param offset the offset to start
* @return the corresponding java int value
*/
public static int getValue(final byte[] bytes, final int offset) {
int value = (bytes[offset + 1] << BYTE_1_SHIFT) & BYTE_1_MASK;
value += (bytes[offset] & BYTE_MASK);
return value;
}
/**
* Helper method to get the value as a java int from a two-byte array
* @param bytes the array of bytes
* @return the corresponding java int value
*/
public static int getValue(final byte[] bytes) {
return getValue(bytes, 0);
}
/**
* Override to make two instances with same value equal.
* @param o an object to compare
* @return true if the objects are equal
*/
@Override
public boolean equals(final Object o) {
if (o == null || !(o instanceof ZipShort)) {
return false;
}
return value == ((ZipShort) o).getValue();
}
/**
* Override to make two instances with same value equal.
* @return the value stored in the ZipShort
*/
@Override
public int hashCode() {
return value;
}
@Override
public Object clone() {
try {
return super.clone();
} catch (final CloneNotSupportedException cnfe) {
// impossible
throw new RuntimeException(cnfe);
}
}
@Override
public String toString() {
return "ZipShort value: " + value;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
/**
* File this entry points to, if it is a symbolic link.
*
* <p>empty string - if entry is not a symbolic link.</p>
*/
private String link = "";
/**
* Is this an entry for a directory?
*/
private boolean dirFlag = false;
/**
* Instance used to calculate checksums.
*/
private CRC32 crc = new CRC32();
/** Constructor for AsiExtraField. */
public AsiExtraField() {
}
/**
* The Header-ID.
* @return the value for the header id for this extrafield
*/
@Override
public ZipShort getHeaderId() {
return HEADER_ID;
}
/**
* Length of the extra field in the local file data - without
* Header-ID or length specifier.
* @return a <code>ZipShort</code> for the length of the data of this extra field
*/
@Override
public ZipShort getLocalFileDataLength() {
return new ZipShort(WORD // CRC
+ 2 // Mode
+ WORD // SizDev
+ 2 // UID
+ 2 // GID
+ getLinkedFile().getBytes().length);
// Uses default charset - see class Javadoc
}
/**
* Delegate to local file data.
* @return the centralDirectory length
*/
@Override
public ZipShort getCentralDirectoryLength() {
return getLocalFileDataLength();
}
/**
* The actual data to put into local file data - without Header-ID
* or length specifier.
* @return get the data
*/
@Override
public byte[] getLocalFileDataData() {
// CRC will be added later
final byte[] data = new byte[getLocalFileDataLength().getValue() - WORD];
System.arraycopy(ZipShort.getBytes(getMode()), 0, data, 0, 2);
final byte[] linkArray = getLinkedFile().getBytes(); // Uses default charset - see class Javadoc
// CheckStyle:MagicNumber OFF
System.arraycopy(ZipLong.getBytes(linkArray.length),
0, data, 2, WORD);
System.arraycopy(ZipShort.getBytes(getUserId()),
0, data, 6, 2);
System.arraycopy(ZipShort.getBytes(getGroupId()),
0, data, 8, 2);
System.arraycopy(linkArray, 0, data, 10, linkArray.length);
// CheckStyle:MagicNumber ON
crc.reset();
crc.update(data);
final long checksum = crc.getValue();
final byte[] result = new byte[data.length + WORD];
System.arraycopy(ZipLong.getBytes(checksum), 0, result, 0, WORD);
System.arraycopy(data, 0, result, WORD, data.length);
return result;
}
/**
* Delegate to local file data.
* @return the local file data
*/
@Override
public byte[] getCentralDirectory
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>Data() {
return getLocalFileDataData();
}
/**
* Set the user id.
* @param uid the user id
*/
public void setUserId(final int uid) {
this.uid = uid;
}
/**
* Get the user id.
* @return the user id
*/
public int getUserId() {
return uid;
}
/**
* Set the group id.
* @param gid the group id
*/
public void setGroupId(final int gid) {
this.gid = gid;
}
/**
* Get the group id.
* @return the group id
*/
public int getGroupId() {
return gid;
}
/**
* Indicate that this entry is a symbolic link to the given filename.
*
* @param name Name of the file this entry links to, empty String
* if it is not a symbolic link.
*/
public void setLinkedFile(final String name) {
link = name;
mode = getMode(mode);
}
/**
* Name of linked file
*
* @return name of the file this entry links to if it is a
* symbolic link, the empty string otherwise.
*/
public String getLinkedFile() {
return link;
}
/**
* Is this entry a symbolic link?
* @return true if this is a symbolic link
*/
public boolean isLink() {
return getLinkedFile().length() != 0;
}
/**
* File mode of this file.
* @param mode the file mode
*/
public void setMode(final int mode) {
this.mode = getMode(mode);
}
/**
* File mode of this file.
* @return the file mode
*/
public int getMode() {
return mode;
}
/**
* Indicate whether this entry is a directory.
* @param dirFlag if true, this entry is a directory
*/
public void setDirectory(final boolean dirFlag) {
this.dirFlag = dirFlag;
mode = getMode(mode);
}
/**
* Is this entry a directory?
* @return true if this entry is a directory
*/
public boolean isDirectory() {
return dirFlag && !isLink();
}
/**
* Populate data from this array as if it was in local file data.
* @param data an array of bytes
* @param offset the start offset
* @param length the number of bytes in the array from offset
* @throws ZipException on error
*/
@Override
public void parseFromLocalFileData(final byte[] data, final int offset, final int length)
throws ZipException {
final long givenChecksum = ZipLong.getValue(data, offset);
final byte[] tmp = new byte[length - WORD];
System.arraycopy(data, offset + WORD, tmp, 0, length - WORD);
crc.reset();
crc.update(tmp);
final long realChecksum = crc.getValue();
if (givenChecksum != realChecksum
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>) {
throw new ZipException("bad CRC checksum "
+ Long.toHexString(givenChecksum)
+ " instead of "
+ Long.toHexString(realChecksum));
}
final int newMode = ZipShort.getValue(tmp, 0);
// CheckStyle:MagicNumber OFF
final byte[] linkArray = new byte[(int) ZipLong.getValue(tmp, 2)];
uid = ZipShort.getValue(tmp, 6);
gid = ZipShort.getValue(tmp, 8);
if (linkArray.length == 0) {
link = "";
} else {
System.arraycopy(tmp, 10, linkArray, 0, linkArray.length);
link = new String(linkArray); // Uses default charset - see class Javadoc
}
// CheckStyle:MagicNumber ON
setDirectory((newMode & DIR_FLAG) != 0);
setMode(newMode);
}
/**
* Doesn't do anything special since this class always uses the
* same data in central directory and local file data.
*/
@Override
public void parseFromCentralDirectoryData(final byte[] buffer, final int offset,
final int length)
throws ZipException {
parseFromLocalFileData(buffer, offset, length);
}
/**
* Get the file mode for given permissions with the correct file type.
* @param mode the mode
* @return the type with the mode
*/
protected int getMode(final int mode) {
int type = FILE_FLAG;
if (isLink()) {
type = LINK_FLAG;
} else if (isDirectory()) {
type = DIR_FLAG;
}
return type | (mode & PERM_MASK);
}
@Override
public Object clone() {
try {
final AsiExtraField cloned = (AsiExtraField) super.clone();
cloned.crc = new CRC32();
return cloned;
} catch (final CloneNotSupportedException cnfe) {
// impossible
throw new RuntimeException(cnfe);
}
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.commons.compress.archivers.zip;
/**
* Info-ZIP Unicode Path Extra Field (0x7075):
*
* <p>Stores the UTF-8 version of the file name field as stored in the
* local header and central directory header.</p>
*
* @see <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE
* APPNOTE.TXT, section 4.6.9</a>
*
* @NotThreadSafe super-class is not thread-safe
*/
public class UnicodePathExtraField extends AbstractUnicodeExtraField {
public static final ZipShort UPATH_ID = new ZipShort(0x7075);
public UnicodePathExtraField () {
}
/**
* Assemble as unicode path extension from the name given as
* text as well as the encoded bytes actually written to the archive.
*
* @param text The file name
* @param bytes the bytes actually written to the archive
* @param off The offset of the encoded filename in <code>bytes</code>.
* @param len The length of the encoded filename or comment in
* <code>bytes</code>.
*/
public UnicodePathExtraField(final String text, final byte[] bytes, final int off, final int len) {
super(text, bytes, off, len);
}
/**
* Assemble as unicode path extension from the name given as
* text as well as the encoded bytes actually written to the archive.
*
* @param name The file name
* @param bytes the bytes actually written to the archive
*/
public UnicodePathExtraField(final String name, final byte[] bytes) {
super(name, bytes);
}
@Override
public ZipShort getHeaderId() {
return UPATH_ID;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>Utils.skip(this, entryEnd - offset);
currentEntry = null;
}
if (offset == 0) {
final byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.HEADER);
final byte[] realized = new byte[expected.length];
final int read = IOUtils.readFully(this, realized);
if (read != expected.length) {
throw new IOException("failed to read header. Occured at byte: " + getBytesRead());
}
for (int i = 0; i < expected.length; i++) {
if (expected[i] != realized[i]) {
throw new IOException("invalid header " + ArchiveUtils.toAsciiString(realized));
}
}
}
if (offset % 2 != 0 && read() < 0) {
// hit eof
return null;
}
if (input.available() == 0) {
return null;
}
IOUtils.readFully(this, NAME_BUF);
IOUtils.readFully(this, LAST_MODIFIED_BUF);
IOUtils.readFully(this, ID_BUF);
final int userId = asInt(ID_BUF, true);
IOUtils.readFully(this, ID_BUF);
IOUtils.readFully(this, FILE_MODE_BUF);
IOUtils.readFully(this, LENGTH_BUF);
{
final byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.TRAILER);
final byte[] realized = new byte[expected.length];
final int read = IOUtils.readFully(this, realized);
if (read != expected.length) {
throw new IOException("failed to read entry trailer. Occured at byte: " + getBytesRead());
}
for (int i = 0; i < expected.length; i++) {
if (expected[i] != realized[i]) {
throw new IOException("invalid entry trailer. not read the content? Occured at byte: " + getBytesRead());
}
}
}
entryOffset = offset;
// GNU ar uses a '/' to mark the end of the filename; this allows for the use of spaces without the use of an extended filename.
// entry name is stored as ASCII string
String temp = ArchiveUtils.toAsciiString(NAME_BUF).trim();
if (isGNUStringTable(temp)) { // GNU extended filenames entry
currentEntry = readGNUStringTable(LENGTH_BUF);
return getNextArEntry();
}
long len = asLong(LENGTH_BUF);
if (temp.endsWith("/")) { // GNU terminator
temp = temp.substring(0, temp.length() - 1);
} else if (isGNULongName(temp)) {
final int off = Integer.parseInt(temp.substring(1));// get the offset
temp = getExtendedName(off); // convert to the long name
} else if (isBSDLongName(temp)) {
temp = getBSDLongName(temp);
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
// entry length contained the length of the file name in
// addition to the real length of the entry.
// assume file name was ASCII, there is no "standard" otherwise
final int nameLen = temp.length();
len -= nameLen;
entryOffset += nameLen;
}
currentEntry = new ArArchiveEntry(temp, len, userId,
asInt(ID_BUF, true),
asInt(FILE_MODE_BUF, 8),
asLong(LAST_MODIFIED_BUF));
return currentEntry;
}
/**
* Get an extended name from the GNU extended name buffer.
*
* @param offset pointer to entry within the buffer
* @return the extended file name; without trailing "/" if present.
* @throws IOException if name not found or buffer not set up
*/
private String getExtendedName(final int offset) throws IOException {
if (namebuffer == null) {
throw new IOException("Cannot process GNU long filename as no // record was found");
}
for (int i = offset; i < namebuffer.length; i++) {
if (namebuffer[i] == '\012' || namebuffer[i] == 0) {
if (namebuffer[i - 1] == '/') {
i--; // drop trailing /
}
return ArchiveUtils.toAsciiString(namebuffer, offset, i - offset);
}
}
throw new IOException("Failed to read entry: " + offset);
}
private long asLong(final byte[] byteArray) {
return Long.parseLong(ArchiveUtils.toAsciiString(byteArray).trim());
}
private int asInt(final byte[] byteArray) {
return asInt(byteArray, 10, false);
}
private int asInt(final byte[] byteArray, final boolean treatBlankAsZero) {
return asInt(byteArray, 10, treatBlankAsZero);
}
private int asInt(final byte[] byteArray, final int base) {
return asInt(byteArray, base, false);
}
private int asInt(final byte[] byteArray, final int base, final boolean treatBlankAsZero) {
final String string = ArchiveUtils.toAsciiString(byteArray).trim();
if (string.length() == 0 && treatBlankAsZero) {
return 0;
}
return Integer.parseInt(string, base);
}
/*
* (non-Javadoc)
*
* @see
* org.apache.commons.compress.archivers.ArchiveInputStream#getNextEntry()
*/
@Override
public ArchiveEntry getNextEntry() throws IOException {
return getNextArEntry();
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#close()
*/
@Override
public void close() throws IOException {
if (!closed) {
closed = true;
input.close();
}
currentEntry = null;
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read(byte[], int
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>, int)
*/
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
int toRead = len;
if (currentEntry != null) {
final long entryEnd = entryOffset + currentEntry.getLength();
if (len > 0 && entryEnd > offset) {
toRead = (int) Math.min(len, entryEnd - offset);
} else {
return -1;
}
}
final int ret = this.input.read(b, off, toRead);
count(ret);
offset += ret > 0 ? ret : 0;
return ret;
}
/**
* Checks if the signature matches ASCII "!<arch>" followed by a single LF
* control character
*
* @param signature
* the bytes to check
* @param length
* the number of bytes to check
* @return true, if this stream is an Ar archive stream, false otherwise
*/
public static boolean matches(final byte[] signature, final int length) {
// 3c21 7261 6863 0a3e
if (length < 8) {
return false;
}
if (signature[0] != 0x21) {
return false;
}
if (signature[1] != 0x3c) {
return false;
}
if (signature[2] != 0x61) {
return false;
}
if (signature[3] != 0x72) {
return false;
}
if (signature[4] != 0x63) {
return false;
}
if (signature[5] != 0x68) {
return false;
}
if (signature[6] != 0x3e) {
return false;
}
if (signature[7] != 0x0a) {
return false;
}
return true;
}
static final String BSD_LONGNAME_PREFIX = "#1/";
private static final int BSD_LONGNAME_PREFIX_LEN =
BSD_LONGNAME_PREFIX.length();
private static final String BSD_LONGNAME_PATTERN =
"^" + BSD_LONGNAME_PREFIX + "\\d+";
/**
* Does the name look like it is a long name (or a name containing
* spaces) as encoded by BSD ar?
*
* <p>From the FreeBSD ar(5) man page:</p>
* <pre>
* BSD In the BSD variant, names that are shorter than 16
* characters and without embedded spaces are stored
* directly in this field. If a name has an embedded
* space, or if it is longer than 16 characters, then
* the string "#1/" followed by the decimal represen-
* tation of the length of the file name is placed in
* this field. The actual file name is stored
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> immedi-
* ately after the archive header. The content of the
* archive member follows the file name. The ar_size
* field of the header (see below) will then hold the
* sum of the size of the file name and the size of
* the member.
* </pre>
*
* @since 1.3
*/
private static boolean isBSDLongName(final String name) {
return name != null && name.matches(BSD_LONGNAME_PATTERN);
}
/**
* Reads the real name from the current stream assuming the very
* first bytes to be read are the real file name.
*
* @see #isBSDLongName
*
* @since 1.3
*/
private String getBSDLongName(final String bsdLongName) throws IOException {
final int nameLen =
Integer.parseInt(bsdLongName.substring(BSD_LONGNAME_PREFIX_LEN));
final byte[] name = new byte[nameLen];
final int read = IOUtils.readFully(this, name);
if (read != nameLen) {
throw new EOFException();
}
return ArchiveUtils.toAsciiString(name);
}
private static final String GNU_STRING_TABLE_NAME = "//";
/**
* Is this the name of the "Archive String Table" as used by
* SVR4/GNU to store long file names?
*
* <p>GNU ar stores multiple extended filenames in the data section
* of a file with the name "//", this record is referred to by
* future headers.</p>
*
* <p>A header references an extended filename by storing a "/"
* followed by a decimal offset to the start of the filename in
* the extended filename data section.</p>
*
* <p>The format of the "//" file itself is simply a list of the
* long filenames, each separated by one or more LF
* characters. Note that the decimal offsets are number of
* characters, not line or string number within the "//" file.</p>
*/
private static boolean isGNUStringTable(final String name) {
return GNU_STRING_TABLE_NAME.equals(name);
}
/**
* Reads the GNU archive String Table.
*
* @see #isGNUStringTable
*/
private ArArchiveEntry readGNUStringTable(final byte[] length) throws IOException {
final int bufflen = asInt(length); // Assume length will fit in an int
namebuffer = new byte[bufflen];
final int read = IOUtils.readFully(this, namebuffer, 0, bufflen);
if (read != bufflen){
throw new IOException("Failed to read complete // record: expected="
+ bufflen + " read=" + read);
}
return new ArArchiveEntry(GNU_STRING_TABLE_NAME, bufflen);
}
private static final String GNU_LONGNAME_PATTERN = "^/\\d+";
/**
* Does the name look like it
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> is a long name (or a name containing
* spaces) as encoded by SVR4/GNU ar?
*
* @see #isGNUStringTable
*/
private boolean isGNULongName(final String name) {
return name != null && name.matches(GNU_LONGNAME_PATTERN);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers;
/**
* Exception thrown by ArchiveStreamFactory if a format is requested/detected that doesn't support streaming.
*
* @since 1.8
*/
public class StreamingNotSupportedException extends ArchiveException {
private static final long serialVersionUID = 1L;
private final String format;
/**
* Creates a new StreamingNotSupportedException.
*
* @param format the format that has been requested/detected.
*/
public StreamingNotSupportedException(final String format) {
super("The " + format + " doesn't support streaming.");
this.format = format;
}
/**
* Returns the format that has been requested/detected.
*
* @return the format that has been requested/detected.
*/
public String getFormat() {
return format;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress;
import static org.junit.Assert.*;
import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.utils.IOUtils;
import org.junit.After;
import org.junit.Before;
public abstract class AbstractTestCase {
protected File dir;
protected File resultDir;
private File archive; // used to delete the archive in tearDown
protected List<String> archiveList; // Lists the content of the archive as originally created
protected ArchiveStreamFactory factory = new ArchiveStreamFactory();
@Before
public void setUp() throws Exception {
dir = mkdir("dir");
resultDir = mkdir("dir-result");
archive = null;
}
public static File mkdir(final String name) throws IOException {
final File f = File.createTempFile(name, "");
f.delete();
f.mkdir();
return f;
}
public static File getFile(final String path) throws IOException {
final URL url = AbstractTestCase.class.getClassLoader().getResource(path);
if (url == null) {
throw new FileNotFoundException("couldn't find " + path);
}
URI uri = null;
try {
uri = url.toURI();
} catch (final java.net.URISyntaxException ex) {
throw new IOException(ex);
}
return new File(uri);
}
@After
public void tearDown
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>() throws Exception {
rmdir(dir);
rmdir(resultDir);
dir = resultDir = null;
if (!tryHardToDelete(archive)) {
// Note: this exception won't be shown if the test has already failed
throw new Exception("Could not delete "+archive.getPath());
}
}
public static void rmdir(final File f) {
final String[] s = f.list();
if (s != null) {
for (final String element : s) {
final File file = new File(f, element);
if (file.isDirectory()){
rmdir(file);
}
final boolean ok = tryHardToDelete(file);
if (!ok && file.exists()){
System.out.println("Failed to delete "+element+" in "+f.getPath());
}
}
}
tryHardToDelete(f); // safer to delete and check
if (f.exists()){
throw new Error("Failed to delete "+f.getPath());
}
}
private static final boolean ON_WINDOWS =
System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows");
/**
* Accommodate Windows bug encountered in both Sun and IBM JDKs.
* Others possible. If the delete does not work, call System.gc(),
* wait a little and try again.
*
* @return whether deletion was successful
* @since Stolen from FileUtils in Ant 1.8.0
*/
public static boolean tryHardToDelete(final File f) {
if (f != null && f.exists() && !f.delete()) {
if (ON_WINDOWS) {
System.gc();
}
try {
Thread.sleep(10);
} catch (final InterruptedException ex) {
// Ignore Exception
}
return f.delete();
}
return true;
}
/**
* Creates an archive of textbased files in several directories. The
* archivername is the factory identifier for the archiver, for example zip,
* tar, cpio, jar, ar. The archive is created as a temp file.
*
* The archive contains the following files:
* <ul>
* <li>testdata/test1.xml</li>
* <li>testdata/test2.xml</li>
* <li>test/test3.xml</li>
* <li>bla/test4.xml</li>
* <li>bla/test5.xml</li>
* <li>bla/blubber/test6.xml</li>
* <li>test.txt</li>
* <li>something/bla</li>
* <li>test with spaces.txt</li>
* </ul>
*
* @param archivename
* the identifier of this archive
* @return the newly created file
* @throws Exception
* in case something goes wrong
*/
protected File createArchive(final String archivename) throws Exception {
ArchiveOutputStream out =
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> null;
OutputStream stream = null;
try {
archive = File.createTempFile("test", "." + archivename);
archive.deleteOnExit();
archiveList = new ArrayList<>();
stream = new FileOutputStream(archive);
out = factory.createArchiveOutputStream(archivename, stream);
final File file1 = getFile("test1.xml");
final File file2 = getFile("test2.xml");
final File file3 = getFile("test3.xml");
final File file4 = getFile("test4.xml");
final File file5 = getFile("test.txt");
final File file6 = getFile("test with spaces.txt");
addArchiveEntry(out, "testdata/test1.xml", file1);
addArchiveEntry(out, "testdata/test2.xml", file2);
addArchiveEntry(out, "test/test3.xml", file3);
addArchiveEntry(out, "bla/test4.xml", file4);
addArchiveEntry(out, "bla/test5.xml", file4);
addArchiveEntry(out, "bla/blubber/test6.xml", file4);
addArchiveEntry(out, "test.txt", file5);
addArchiveEntry(out, "something/bla", file6);
addArchiveEntry(out, "test with spaces.txt", file6);
out.finish();
return archive;
} finally {
if (out != null) {
out.close();
} else if (stream != null) {
stream.close();
}
}
}
/**
* Add an entry to the archive, and keep track of the names in archiveList.
*
* @param out
* @param file1
* @throws IOException
* @throws FileNotFoundException
*/
private void addArchiveEntry(final ArchiveOutputStream out, final String filename, final File infile)
throws IOException, FileNotFoundException {
final ArchiveEntry entry = out.createArchiveEntry(infile, filename);
out.putArchiveEntry(entry);
IOUtils.copy(new FileInputStream(infile), out);
out.closeArchiveEntry();
archiveList.add(filename);
}
/**
* Create an empty archive.
* @param archivename
* @return the archive File
* @throws Exception
*/
protected File createEmptyArchive(final String archivename) throws Exception {
ArchiveOutputStream out = null;
OutputStream stream = null;
archiveList = new ArrayList<>();
try {
archive = File.createTempFile("empty", "." + archivename);
archive.deleteOnExit();
stream = new FileOutputStream(archive);
out = factory.createArchiveOutputStream(archivename, stream);
out.finish();
} finally {
if (out != null) {
out.close();
} else if (stream != null) {
stream.close();
}
}
return archive;
}
/**
* Create an archive with a single file "test1.xml".
*
* @param archivename
*
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> @return the archive File
* @throws Exception
*/
protected File createSingleEntryArchive(final String archivename) throws Exception {
ArchiveOutputStream out = null;
OutputStream stream = null;
archiveList = new ArrayList<>();
try {
archive = File.createTempFile("empty", "." + archivename);
archive.deleteOnExit();
stream = new FileOutputStream(archive);
out = factory.createArchiveOutputStream(archivename, stream);
// Use short file name so does not cause problems for ar
addArchiveEntry(out, "test1.xml", getFile("test1.xml"));
out.finish();
} finally {
if (out != null) {
out.close();
} else if (stream != null) {
stream.close();
}
}
return archive;
}
/**
* Checks if an archive contains all expected files.
*
* @param archive
* the archive to check
* @param expected
* a list with expected string filenames
* @throws Exception
*/
protected void checkArchiveContent(final File archive, final List<String> expected)
throws Exception {
try (InputStream is = new FileInputStream(archive)) {
final BufferedInputStream buf = new BufferedInputStream(is);
final ArchiveInputStream in = factory.createArchiveInputStream(buf);
this.checkArchiveContent(in, expected);
}
}
/**
* Checks that an archive input stream can be read, and that the file data matches file sizes.
*
* @param in
* @param expected list of expected entries or {@code null} if no check of names desired
* @throws Exception
*/
protected void checkArchiveContent(final ArchiveInputStream in, final List<String> expected)
throws Exception {
checkArchiveContent(in, expected, true);
}
/**
* Checks that an archive input stream can be read, and that the file data matches file sizes.
*
* @param in
* @param expected list of expected entries or {@code null} if no check of names desired
* @param cleanUp Cleans up resources if true
* @return returns the created result file if cleanUp = false, or null otherwise
* @throws Exception
*/
protected File checkArchiveContent(final ArchiveInputStream in, final List<String> expected, final boolean cleanUp)
throws Exception {
final File result = mkdir("dir-result");
result.deleteOnExit();
try {
ArchiveEntry entry = null;
while ((entry = in.getNextEntry()) != null) {
final File outfile = new File(result.getCanonicalPath() + "/result/"
+ entry.getName());
long copied=0;
if (entry.isDirectory()){
outfile.mkdirs();
} else {
outfile.getParentFile().mkdirs();
try (OutputStream out = new FileOutputStream(outfile)) {
copied = IOUtils.copy(in, out);
}
}
final long size = entry.getSize();
if (size != ArchiveEntry.SIZE_UNKNOWN) {
assertEquals("Entry.size should equal bytes read.",size
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>, copied);
}
if (!outfile.exists()) {
fail("extraction failed: " + entry.getName());
}
if (expected != null && !expected.remove(getExpectedString(entry))) {
fail("unexpected entry: " + getExpectedString(entry));
}
}
in.close();
if (expected != null && expected.size() > 0) {
fail(expected.size() + " missing entries: " + Arrays.toString(expected.toArray()));
}
if (expected != null) {
assertEquals(0, expected.size());
}
} finally {
if (cleanUp) {
rmdir(result);
}
}
return result;
}
/**
* Override this method to change what is to be compared in the List.
* For example, size + name instead of just name.
*
* @param entry
* @return returns the entry name
*/
protected String getExpectedString(final ArchiveEntry entry) {
return entry.getName();
}
/**
* Creates a temporary directory and a temporary file inside that
* directory, returns both of them (the directory is the first
* element of the two element array).
*/
protected File[] createTempDirAndFile() throws IOException {
final File tmpDir = createTempDir();
final File tmpFile = File.createTempFile("testfile", "", tmpDir);
tmpFile.deleteOnExit();
try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
fos.write(new byte[] { 'f', 'o', 'o' });
return new File[] { tmpDir, tmpFile };
}
}
protected File createTempDir() throws IOException {
final File tmpDir = mkdir("testdir");
tmpDir.deleteOnExit();
return tmpDir;
}
protected void closeQuietly(final Closeable closeable){
if (closeable != null) {
try {
closeable.close();
} catch (final IOException ignored) {
// ignored
}
}
}
protected static interface StreamWrapper<I extends InputStream> {
I wrap(InputStream in) throws Exception;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.zip;
import java.util.zip.ZipException;
import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD;
import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
/**
* Holds size and other extended information for entries that use Zip64
* features.
*
* <p>Currently Commons Compress doesn't support encrypting the
* central directory so the note in APPNOTE.TXT about masking doesn't
* apply.</p>
*
* <p>The implementation relies on data being read from the local file
* header and assumes that both size values are always present.</p>
*
* @see <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE
* APPNOTE.TXT, section 4.5.3</a>
*
* @since 1.2
* @NotThreadSafe
*/
public class Zip64ExtendedInformationExtraField implements ZipExtraField {
static final ZipShort HEADER_ID = new ZipShort(0x0001);
private static final String LFH_MUST_HAVE_BOTH_SIZES_MSG =
"Zip64 extended information must contain"
+ " both size values in the local file header.";
private static final byte[] EMPTY = new byte[0];
private ZipEightByteInteger size, compressedSize, relativeHeaderOffset;
private ZipLong diskStart;
/**
* Stored in {@link #parseFromCentralDirectoryData
* parseFromCentralDirectoryData} so it can be reused when ZipFile
* calls {@link #reparseCentralDirectoryData
* reparseCentralDirectoryData}.
*
* <p>Not used for anything else</p>
*
* @since 1.3
*/
private byte[] rawCentralDirectoryData;
/**
* This constructor should only be used by the code that reads
* archives inside of Commons Compress.
*/
public Zip64ExtendedInformationExtraField() { }
/**
* Creates an extra field based on the original and compressed size.
*
* @param size
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> the entry's original size
* @param compressedSize the entry's compressed size
*
* @throws IllegalArgumentException if size or compressedSize is null
*/
public Zip64ExtendedInformationExtraField(final ZipEightByteInteger size,
final ZipEightByteInteger compressedSize) {
this(size, compressedSize, null, null);
}
/**
* Creates an extra field based on all four possible values.
*
* @param size the entry's original size
* @param compressedSize the entry's compressed size
* @param relativeHeaderOffset the entry's offset
* @param diskStart the disk start
*
* @throws IllegalArgumentException if size or compressedSize is null
*/
public Zip64ExtendedInformationExtraField(final ZipEightByteInteger size,
final ZipEightByteInteger compressedSize,
final ZipEightByteInteger relativeHeaderOffset,
final ZipLong diskStart) {
this.size = size;
this.compressedSize = compressedSize;
this.relativeHeaderOffset = relativeHeaderOffset;
this.diskStart = diskStart;
}
@Override
public ZipShort getHeaderId() {
return HEADER_ID;
}
@Override
public ZipShort getLocalFileDataLength() {
return new ZipShort(size != null ? 2 * DWORD : 0);
}
@Override
public ZipShort getCentralDirectoryLength() {
return new ZipShort((size != null ? DWORD : 0)
+ (compressedSize != null ? DWORD : 0)
+ (relativeHeaderOffset != null ? DWORD : 0)
+ (diskStart != null ? WORD : 0));
}
@Override
public byte[] getLocalFileDataData() {
if (size != null || compressedSize != null) {
if (size == null || compressedSize == null) {
throw new IllegalArgumentException(LFH_MUST_HAVE_BOTH_SIZES_MSG);
}
final byte[] data = new byte[2 * DWORD];
addSizes(data);
return data;
}
return EMPTY;
}
@Override
public byte[] getCentralDirectoryData() {
final byte[] data = new byte[getCentralDirectoryLength().getValue()];
int off = addSizes(data);
if (relativeHeaderOffset != null) {
System.arraycopy(relativeHeaderOffset.getBytes(), 0, data, off, DWORD);
off += DWORD;
}
if (diskStart != null) {
System.arraycopy(diskStart.getBytes(), 0, data, off, WORD);
off += WORD;
}
return data;
}
@Override
public void parseFromLocalFileData(final byte[] buffer, int offset, final int length)
throws ZipException {
if (length == 0) {
// no local file data at all, may happen if an archive
// only holds a ZIP64 extended information extra field
// inside the central directory but not inside the local
// file header
return;
}
if (length < 2 * DWORD) {
throw new ZipException(LFH
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>_MUST_HAVE_BOTH_SIZES_MSG);
}
size = new ZipEightByteInteger(buffer, offset);
offset += DWORD;
compressedSize = new ZipEightByteInteger(buffer, offset);
offset += DWORD;
int remaining = length - 2 * DWORD;
if (remaining >= DWORD) {
relativeHeaderOffset = new ZipEightByteInteger(buffer, offset);
offset += DWORD;
remaining -= DWORD;
}
if (remaining >= WORD) {
diskStart = new ZipLong(buffer, offset);
offset += WORD;
remaining -= WORD;
}
}
@Override
public void parseFromCentralDirectoryData(final byte[] buffer, int offset,
final int length)
throws ZipException {
// store for processing in reparseCentralDirectoryData
rawCentralDirectoryData = new byte[length];
System.arraycopy(buffer, offset, rawCentralDirectoryData, 0, length);
// if there is no size information in here, we are screwed and
// can only hope things will get resolved by LFH data later
// But there are some cases that can be detected
// * all data is there
// * length == 24 -> both sizes and offset
// * length % 8 == 4 -> at least we can identify the diskStart field
if (length >= 3 * DWORD + WORD) {
parseFromLocalFileData(buffer, offset, length);
} else if (length == 3 * DWORD) {
size = new ZipEightByteInteger(buffer, offset);
offset += DWORD;
compressedSize = new ZipEightByteInteger(buffer, offset);
offset += DWORD;
relativeHeaderOffset = new ZipEightByteInteger(buffer, offset);
} else if (length % DWORD == WORD) {
diskStart = new ZipLong(buffer, offset + length - WORD);
}
}
/**
* Parses the raw bytes read from the central directory extra
* field with knowledge which fields are expected to be there.
*
* <p>All four fields inside the zip64 extended information extra
* field are optional and must only be present if their corresponding
* entry inside the central directory contains the correct magic
* value.</p>
*
* @param hasUncompressedSize flag to read from central directory
* @param hasCompressedSize flag to read from central directory
* @param hasRelativeHeaderOffset flag to read from central directory
* @param hasDiskStart flag to read from central directory
* @throws ZipException on error
*/
public void reparseCentralDirectoryData(final boolean hasUncompressedSize,
final boolean hasCompressedSize,
final boolean hasRelativeHeaderOffset,
final boolean hasDiskStart)
throws ZipException {
if (rawCentralDirectoryData != null) {
final int expectedLength = (hasUncompressedSize ? DWORD : 0)
+ (hasCompressedSize ? DWORD : 0)
+ (hasRelativeHeaderOffset ? DWORD : 0)
+ (hasDiskStart ? WORD : 0);
if (rawCentralDirectoryData.length <
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> expectedLength) {
throw new ZipException("central directory zip64 extended"
+ " information extra field's length"
+ " doesn't match central directory"
+ " data. Expected length "
+ expectedLength + " but is "
+ rawCentralDirectoryData.length);
}
int offset = 0;
if (hasUncompressedSize) {
size = new ZipEightByteInteger(rawCentralDirectoryData, offset);
offset += DWORD;
}
if (hasCompressedSize) {
compressedSize = new ZipEightByteInteger(rawCentralDirectoryData,
offset);
offset += DWORD;
}
if (hasRelativeHeaderOffset) {
relativeHeaderOffset =
new ZipEightByteInteger(rawCentralDirectoryData, offset);
offset += DWORD;
}
if (hasDiskStart) {
diskStart = new ZipLong(rawCentralDirectoryData, offset);
offset += WORD;
}
}
}
/**
* The uncompressed size stored in this extra field.
* @return The uncompressed size stored in this extra field.
*/
public ZipEightByteInteger getSize() {
return size;
}
/**
* The uncompressed size stored in this extra field.
* @param size The uncompressed size stored in this extra field.
*/
public void setSize(final ZipEightByteInteger size) {
this.size = size;
}
/**
* The compressed size stored in this extra field.
* @return The compressed size stored in this extra field.
*/
public ZipEightByteInteger getCompressedSize() {
return compressedSize;
}
/**
* The uncompressed size stored in this extra field.
* @param compressedSize The uncompressed size stored in this extra field.
*/
public void setCompressedSize(final ZipEightByteInteger compressedSize) {
this.compressedSize = compressedSize;
}
/**
* The relative header offset stored in this extra field.
* @return The relative header offset stored in this extra field.
*/
public ZipEightByteInteger getRelativeHeaderOffset() {
return relativeHeaderOffset;
}
/**
* The relative header offset stored in this extra field.
* @param rho The relative header offset stored in this extra field.
*/
public void setRelativeHeaderOffset(final ZipEightByteInteger rho) {
relativeHeaderOffset = rho;
}
/**
* The disk start number stored in this extra field.
* @return The disk start number stored in this extra field.
*/
public ZipLong getDiskStartNumber() {
return diskStart;
}
/**
* The disk start number stored in this extra field.
* @param ds The disk start number stored in this extra field.
*/
public void setDiskStartNumber(final ZipLong ds) {
diskStart = ds;
}
private int addSizes(final byte[] data) {
int off = 0;
if (size != null) {
System.arraycopy(size.getBytes(), 0, data, 0,
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.jar;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
/**
* Implements an input stream that can read entries from jar files.
*
* @NotThreadSafe
*/
public class JarArchiveInputStream extends ZipArchiveInputStream {
/**
* Creates an instance from the input stream using the default encoding.
*
* @param inputStream the input stream to wrap
*/
public JarArchiveInputStream( final InputStream inputStream ) {
super(inputStream);
}
/**
* Creates an instance from the input stream using the specified encoding.
*
* @param inputStream the input stream to wrap
* @param encoding the encoding to use
* @since 1.10
*/
public JarArchiveInputStream( final InputStream inputStream, final String encoding ) {
super(inputStream, encoding);
}
public JarArchiveEntry getNextJarEntry() throws IOException {
final ZipArchiveEntry entry = getNextZipEntry();
return entry == null ? null : new JarArchiveEntry(entry);
}
@Override
public ArchiveEntry getNextEntry() throws IOException {
return getNextJarEntry();
}
/**
* Checks if the signature matches what is expected for a jar file
* (in this case it is the same as for a zip file).
*
* @param signature
* the bytes to check
* @param length
* the number of bytes to check
* @return true, if this stream is a jar archive stream, false otherwise
*/
public static boolean matches(final byte[] signature, final int length ) {
return ZipArchiveInputStream.matches(signature, length);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.zip;
import java.util.zip.ZipException;
/**
* General format of extra field data.
*
* <p>Extra fields usually appear twice per file, once in the local
* file data and once in the central directory. Usually they are the
* same, but they don't have to be. {@link
* java.util.zip.ZipOutputStream java.util.zip.ZipOutputStream} will
* only use the local file data in both places.</p>
*
*/
public interface ZipExtraField {
/**
* The Header-ID.
*
* @return The HeaderId value
*/
ZipShort getHeaderId();
/**
* Length of the extra field in the local file data - without
* Header-ID or length specifier.
* @return the length of the field in the local file data
*/
ZipShort getLocalFileDataLength();
/**
* Length of the extra field in the central directory - without
* Header-ID or length specifier.
* @return the length of the field in the central directory
*/
ZipShort getCentralDirectoryLength();
/**
* The actual data to put into local file data - without Header-ID
* or length specifier.
* @return the data
*/
byte[] getLocalFileDataData();
/**
* The actual data to put into central directory - without Header-ID or
* length specifier.
* @return the data
*/
byte[] getCentralDirectoryData();
/**
* Populate data from this array as if it was in local file data.
*
* @param buffer the buffer to read data from
* @param offset offset into buffer to read data
* @param length the length of data
* @throws ZipException on error
*/
void parseFromLocalFileData(byte[] buffer, int offset, int length)
throws ZipException;
/**
* Populate data from this array as if it was in central directory data.
*
* @param buffer the buffer to read data from
* @param offset offset into buffer to read data
* @param length the length of data
* @throws ZipException on error
*/
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
void parseFromCentralDirectoryData(byte[] buffer, int offset, int length)
throws ZipException;
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.tar;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipEncoding;
import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
import org.apache.commons.compress.utils.CharsetNames;
import org.apache.commons.compress.utils.CountingOutputStream;
/**
* The TarOutputStream writes a UNIX tar archive as an OutputStream.
* Methods are provided to put entries, and then write their contents
* by writing to this stream using write().
* @NotThreadSafe
*/
public class TarArchiveOutputStream extends ArchiveOutputStream {
/** Fail if a long file name is required in the archive. */
public static final int LONGFILE_ERROR = 0;
/** Long paths will be truncated in the archive. */
public static final int LONGFILE_TRUNCATE = 1;
/** GNU tar extensions are used to store long file names in the archive. */
public static final int LONGFILE_GNU = 2;
/** POSIX/PAX extensions are used to store long file names in the archive. */
public static final int LONGFILE_POSIX = 3;
/** Fail if a big number (e.g. size > 8GiB) is required in the archive. */
public static final int BIGNUMBER_ERROR = 0;
/** star/GNU tar/BSD tar extensions are used to store big number in the archive. */
public static final int BIGNUMBER_STAR = 1;
/** POSIX/PAX extensions are used to store big numbers in the archive. */
public static final int BIGNUMBER_POSIX = 2;
private long currSize;
private String
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> currName;
private long currBytes;
private final byte[] recordBuf;
private int assemLen;
private final byte[] assemBuf;
private int longFileMode = LONGFILE_ERROR;
private int bigNumberMode = BIGNUMBER_ERROR;
private int recordsWritten;
private final int recordsPerBlock;
private final int recordSize;
private boolean closed = false;
/** Indicates if putArchiveEntry has been called without closeArchiveEntry */
private boolean haveUnclosedEntry = false;
/** indicates if this archive is finished */
private boolean finished = false;
private final OutputStream out;
private final ZipEncoding zipEncoding;
// the provided encoding (for unit tests)
final String encoding;
private boolean addPaxHeadersForNonAsciiNames = false;
private static final ZipEncoding ASCII =
ZipEncodingHelper.getZipEncoding("ASCII");
/**
* Constructor for TarInputStream.
* @param os the output stream to use
*/
public TarArchiveOutputStream(final OutputStream os) {
this(os, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE);
}
/**
* Constructor for TarInputStream.
* @param os the output stream to use
* @param encoding name of the encoding to use for file names
* @since 1.4
*/
public TarArchiveOutputStream(final OutputStream os, final String encoding) {
this(os, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE, encoding);
}
/**
* Constructor for TarInputStream.
* @param os the output stream to use
* @param blockSize the block size to use
*/
public TarArchiveOutputStream(final OutputStream os, final int blockSize) {
this(os, blockSize, TarConstants.DEFAULT_RCDSIZE);
}
/**
* Constructor for TarInputStream.
* @param os the output stream to use
* @param blockSize the block size to use
* @param encoding name of the encoding to use for file names
* @since 1.4
*/
public TarArchiveOutputStream(final OutputStream os, final int blockSize,
final String encoding) {
this(os, blockSize, TarConstants.DEFAULT_RCDSIZE, encoding);
}
/**
* Constructor for TarInputStream.
* @param os the output stream to use
* @param blockSize the block size to use
* @param recordSize the record size to use
*/
public TarArchiveOutputStream(final OutputStream os, final int blockSize, final int recordSize) {
this(os, blockSize, recordSize, null);
}
/**
* Constructor for TarInputStream.
* @param os the output stream to use
* @param blockSize the block size to use
* @param recordSize the record size to use
* @param encoding name of the encoding to use for file names
* @since 1.4
*/
public TarArchiveOutputStream(final OutputStream os, final int blockSize,
final int recordSize, final String encoding) {
out = new CountingOutputStream(os);
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
closed = true;
}
}
/**
* Get the record size being used by this stream's TarBuffer.
*
* @return The TarBuffer record size.
*/
public int getRecordSize() {
return this.recordSize;
}
/**
* Put an entry on the output stream. This writes the entry's
* header record and positions the output stream for writing
* the contents of the entry. Once this method is called, the
* stream is ready for calls to write() to write the entry's
* contents. Once the contents are written, closeArchiveEntry()
* <B>MUST</B> be called to ensure that all buffered data
* is completely written to the output stream.
*
* @param archiveEntry The TarEntry to be written to the archive.
* @throws IOException on error
* @throws ClassCastException if archiveEntry is not an instance of TarArchiveEntry
*/
@Override
public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException {
if (finished) {
throw new IOException("Stream has already been finished");
}
final TarArchiveEntry entry = (TarArchiveEntry) archiveEntry;
final Map<String, String> paxHeaders = new HashMap<>();
final String entryName = entry.getName();
final boolean paxHeaderContainsPath = handleLongName(entry, entryName, paxHeaders, "path",
TarConstants.LF_GNUTYPE_LONGNAME, "file name");
final String linkName = entry.getLinkName();
final boolean paxHeaderContainsLinkPath = linkName != null && linkName.length() > 0
&& handleLongName(entry, linkName, paxHeaders, "linkpath",
TarConstants.LF_GNUTYPE_LONGLINK, "link name");
if (bigNumberMode == BIGNUMBER_POSIX) {
addPaxHeadersForBigNumbers(paxHeaders, entry);
} else if (bigNumberMode != BIGNUMBER_STAR) {
failForBigNumbers(entry);
}
if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsPath
&& !ASCII.canEncode(entryName)) {
paxHeaders.put("path", entryName);
}
if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsLinkPath
&& (entry.isLink() || entry.isSymbolicLink())
&& !ASCII.canEncode(linkName)) {
paxHeaders.put("linkpath", linkName);
}
if (paxHeaders.size() > 0) {
writePaxHeaders(entry, entryName, paxHeaders);
}
entry.writeEntryHeader(recordBuf, zipEncoding,
bigNumberMode == BIGNUMBER_STAR);
writeRecord(recordBuf);
currBytes = 0;
if (entry.isDirectory()) {
currSize = 0;
} else {
currSize = entry.getSize();
}
currName = entryName;
haveUnclosedEntry = true;
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>.arraycopy(wBuf, wOffset, recordBuf,
assemLen, aLen);
writeRecord(recordBuf);
currBytes += recordBuf.length;
wOffset += aLen;
numToWrite -= aLen;
assemLen = 0;
} else {
System.arraycopy(wBuf, wOffset, assemBuf, assemLen,
numToWrite);
wOffset += numToWrite;
assemLen += numToWrite;
numToWrite = 0;
}
}
//
// When we get here we have EITHER:
// o An empty "assemble" buffer.
// o No bytes to write (numToWrite == 0)
//
while (numToWrite > 0) {
if (numToWrite < recordBuf.length) {
System.arraycopy(wBuf, wOffset, assemBuf, assemLen,
numToWrite);
assemLen += numToWrite;
break;
}
writeRecord(wBuf, wOffset);
final int num = recordBuf.length;
currBytes += num;
numToWrite -= num;
wOffset += num;
}
}
/**
* Writes a PAX extended header with the given map as contents.
* @since 1.4
*/
void writePaxHeaders(final TarArchiveEntry entry,
final String entryName,
final Map<String, String> headers) throws IOException {
String name = "./PaxHeaders.X/" + stripTo7Bits(entryName);
if (name.length() >= TarConstants.NAMELEN) {
name = name.substring(0, TarConstants.NAMELEN - 1);
}
final TarArchiveEntry pex = new TarArchiveEntry(name,
TarConstants.LF_PAX_EXTENDED_HEADER_LC);
transferModTime(entry, pex);
final StringWriter w = new StringWriter();
for (final Map.Entry<String, String> h : headers.entrySet()) {
final String key = h.getKey();
final String value = h.getValue();
int len = key.length() + value.length()
+ 3 /* blank, equals and newline */
+ 2 /* guess 9 < actual length < 100 */;
String line = len + " " + key + "=" + value + "\n";
int actualLength = line.getBytes(CharsetNames.UTF_8).length;
while (len != actualLength) {
// Adjust for cases where length < 10 or > 100
// or where UTF-8 encoding isn't a single octet
// per character.
// Must be in loop as size may go from 99 to 100 in
// first pass so we'd need a second.
len = actualLength;
line = len + " " + key + "=" + value + "\n";
actualLength = line.getBytes(CharsetNames.UTF_8).length;
}
w.write(line);
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> final byte[] data = w.toString().getBytes(CharsetNames.UTF_8);
pex.setSize(data.length);
putArchiveEntry(pex);
write(data);
closeArchiveEntry();
}
private String stripTo7Bits(final String name) {
final int length = name.length();
final StringBuilder result = new StringBuilder(length);
for (int i = 0; i < length; i++) {
final char stripped = (char) (name.charAt(i) & 0x7F);
if (shouldBeReplaced(stripped)) {
result.append("_");
} else {
result.append(stripped);
}
}
return result.toString();
}
/**
* @return true if the character could lead to problems when used
* inside a TarArchiveEntry name for a PAX header.
*/
private boolean shouldBeReplaced(final char c) {
return c == 0 // would be read as Trailing null
|| c == '/' // when used as last character TAE will consider the PAX header a directory
|| c == '\\'; // same as '/' as slashes get "normalized" on Windows
}
/**
* Write an EOF (end of archive) record to the tar archive.
* An EOF record consists of a record of all zeros.
*/
private void writeEOFRecord() throws IOException {
Arrays.fill(recordBuf, (byte) 0);
writeRecord(recordBuf);
}
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName)
throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
return new TarArchiveEntry(inputFile, entryName);
}
/**
* Write an archive record to the archive.
*
* @param record The record data to write to the archive.
* @throws IOException on error
*/
private void writeRecord(final byte[] record) throws IOException {
if (record.length != recordSize) {
throw new IOException("record to write has length '"
+ record.length
+ "' which is not the record size of '"
+ recordSize + "'");
}
out.write(record);
recordsWritten++;
}
/**
* Write an archive record to the archive, where the record may be
* inside of a larger array buffer. The buffer must be "offset plus
* record size" long.
*
* @param buf The buffer containing the record data to write.
* @param offset The offset of the record data within buf.
* @throws IOException on error
*/
private void writeRecord(final byte[] buf, final int offset) throws IOException {
if (offset + recordSize > buf.length) {
throw new IOException("record has length '" + buf.length
+ "' with offset '" + offset
+ "' which is less than the record size of '"
+ recordSize + "'");
}
out.write(buf, offset
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>, recordSize);
recordsWritten++;
}
private void padAsNeeded() throws IOException {
final int start = recordsWritten % recordsPerBlock;
if (start != 0) {
for (int i = start; i < recordsPerBlock; i++) {
writeEOFRecord();
}
}
}
private void addPaxHeadersForBigNumbers(final Map<String, String> paxHeaders,
final TarArchiveEntry entry) {
addPaxHeaderForBigNumber(paxHeaders, "size", entry.getSize(),
TarConstants.MAXSIZE);
addPaxHeaderForBigNumber(paxHeaders, "gid", entry.getLongGroupId(),
TarConstants.MAXID);
addPaxHeaderForBigNumber(paxHeaders, "mtime",
entry.getModTime().getTime() / 1000,
TarConstants.MAXSIZE);
addPaxHeaderForBigNumber(paxHeaders, "uid", entry.getLongUserId(),
TarConstants.MAXID);
// star extensions by J\u00f6rg Schilling
addPaxHeaderForBigNumber(paxHeaders, "SCHILY.devmajor",
entry.getDevMajor(), TarConstants.MAXID);
addPaxHeaderForBigNumber(paxHeaders, "SCHILY.devminor",
entry.getDevMinor(), TarConstants.MAXID);
// there is no PAX header for file mode
failForBigNumber("mode", entry.getMode(), TarConstants.MAXID);
}
private void addPaxHeaderForBigNumber(final Map<String, String> paxHeaders,
final String header, final long value,
final long maxValue) {
if (value < 0 || value > maxValue) {
paxHeaders.put(header, String.valueOf(value));
}
}
private void failForBigNumbers(final TarArchiveEntry entry) {
failForBigNumber("entry size", entry.getSize(), TarConstants.MAXSIZE);
failForBigNumberWithPosixMessage("group id", entry.getLongGroupId(), TarConstants.MAXID);
failForBigNumber("last modification time",
entry.getModTime().getTime() / 1000,
TarConstants.MAXSIZE);
failForBigNumber("user id", entry.getLongUserId(), TarConstants.MAXID);
failForBigNumber("mode", entry.getMode(), TarConstants.MAXID);
failForBigNumber("major device number", entry.getDevMajor(),
TarConstants.MAXID);
failForBigNumber("minor device number", entry.getDevMinor(),
TarConstants.MAXID);
}
private void failForBigNumber(final String field, final long value, final long maxValue) {
failForBigNumber(field, value, maxValue, "");
}
private void failForBigNumberWithPosixMessage(final String field, final long value, final long maxValue) {
failForBigNumber(field, value, maxValue, " Use STAR or POSIX extensions to overcome this limit");
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
}
private void failForBigNumber(final String field, final long value, final long maxValue, final String additionalMsg) {
if (value < 0 || value > maxValue) {
throw new RuntimeException(field + " '" + value
+ "' is too big ( > "
+ maxValue + " )." + additionalMsg);
}
}
/**
* Handles long file or link names according to the longFileMode setting.
*
* <p>I.e. if the given name is too long to be written to a plain
* tar header then
* <ul>
* <li>it creates a pax header who's name is given by the
* paxHeaderName parameter if longFileMode is POSIX</li>
* <li>it creates a GNU longlink entry who's type is given by
* the linkType parameter if longFileMode is GNU</li>
* <li>it throws an exception if longFileMode is ERROR</li>
* <li>it truncates the name if longFileMode is TRUNCATE</li>
* </ul></p>
*
* @param entry entry the name belongs to
* @param name the name to write
* @param paxHeaders current map of pax headers
* @param paxHeaderName name of the pax header to write
* @param linkType type of the GNU entry to write
* @param fieldName the name of the field
* @return whether a pax header has been written.
*/
private boolean handleLongName(final TarArchiveEntry entry , final String name,
final Map<String, String> paxHeaders,
final String paxHeaderName, final byte linkType, final String fieldName)
throws IOException {
final ByteBuffer encodedName = zipEncoding.encode(name);
final int len = encodedName.limit() - encodedName.position();
if (len >= TarConstants.NAMELEN) {
if (longFileMode == LONGFILE_POSIX) {
paxHeaders.put(paxHeaderName, name);
return true;
} else if (longFileMode == LONGFILE_GNU) {
// create a TarEntry for the LongLink, the contents
// of which are the link's name
final TarArchiveEntry longLinkEntry = new TarArchiveEntry(TarConstants.GNU_LONGLINK, linkType);
longLinkEntry.setSize(len + 1); // +1 for NUL
transferModTime(entry, longLinkEntry);
putArchiveEntry(longLinkEntry);
write(encodedName.array(), encodedName.arrayOffset(), len);
write(0); // NUL terminator
closeArchiveEntry();
} else if (longFileMode != LONGFILE_TRUNCATE) {
throw new RuntimeException(fieldName + " '" + name
+ "' is too long ( > "
+ TarConstants.NAMELEN + " bytes)");
}
}
return false;
}
private void transferModTime(final TarArchiveEntry from, final TarArchiveEntry to) {
Date from
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.commons.compress.archivers.arj;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.zip.CRC32;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.utils.BoundedInputStream;
import org.apache.commons.compress.utils.CRC32VerifyingInputStream;
import org.apache.commons.compress.utils.IOUtils;
/**
* Implements the "arj" archive format as an InputStream.
* <p>
* <a href="http://farmanager.com/svn/trunk/plugins/multiarc/arc.doc/arj.txt">Reference</a>
* @NotThreadSafe
* @since 1.6
*/
public class ArjArchiveInputStream extends ArchiveInputStream {
private static final int ARJ_MAGIC_1 = 0x60;
private static final int ARJ_MAGIC_2 = 0xEA;
private final DataInputStream in;
private final String charsetName;
private final MainHeader mainHeader;
private LocalFileHeader currentLocalFileHeader = null;
private InputStream currentInputStream = null;
/**
* Constructs the ArjInputStream, taking ownership of the inputStream that is passed in.
* @param inputStream the underlying stream, whose ownership is taken
* @param charsetName the charset used for file names and comments
* in the archive. May be {@code null} to use the platform default.
* @throws ArchiveException if an exception occurs while reading
*/
public ArjArchiveInputStream(final InputStream inputStream,
final String charsetName) throws ArchiveException {
in = new DataInputStream(inputStream);
this.charsetName = charsetName;
try {
mainHeader = readMainHeader();
if ((mainHeader.arjFlags & Main
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>Header.Flags.GARBLED) != 0) {
throw new ArchiveException("Encrypted ARJ files are unsupported");
}
if ((mainHeader.arjFlags & MainHeader.Flags.VOLUME) != 0) {
throw new ArchiveException("Multi-volume ARJ files are unsupported");
}
} catch (final IOException ioException) {
throw new ArchiveException(ioException.getMessage(), ioException);
}
}
/**
* Constructs the ArjInputStream, taking ownership of the inputStream that is passed in,
* and using the CP437 character encoding.
* @param inputStream the underlying stream, whose ownership is taken
* @throws ArchiveException if an exception occurs while reading
*/
public ArjArchiveInputStream(final InputStream inputStream)
throws ArchiveException {
this(inputStream, "CP437");
}
@Override
public void close() throws IOException {
in.close();
}
private int read8(final DataInputStream dataIn) throws IOException {
final int value = dataIn.readUnsignedByte();
count(1);
return value;
}
private int read16(final DataInputStream dataIn) throws IOException {
final int value = dataIn.readUnsignedShort();
count(2);
return Integer.reverseBytes(value) >>> 16;
}
private int read32(final DataInputStream dataIn) throws IOException {
final int value = dataIn.readInt();
count(4);
return Integer.reverseBytes(value);
}
private String readString(final DataInputStream dataIn) throws IOException {
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nextByte;
while ((nextByte = dataIn.readUnsignedByte()) != 0) {
buffer.write(nextByte);
}
if (charsetName != null) {
return new String(buffer.toByteArray(), charsetName);
}
// intentionally using the default encoding as that's the contract for a null charsetName
return new String(buffer.toByteArray());
}
private void readFully(final DataInputStream dataIn, final byte[] b)
throws IOException {
dataIn.readFully(b);
count(b.length);
}
private byte[] readHeader() throws IOException {
boolean found = false;
byte[] basicHeaderBytes = null;
do {
int first = 0;
int second = read8(in);
do {
first = second;
second = read8(in);
} while (first != ARJ_MAGIC_1 && second != ARJ_MAGIC_2);
final int basicHeaderSize = read16(in);
if (basicHeaderSize == 0) {
// end of archive
return null;
}
if (basicHeaderSize <= 2600) {
basicHeaderBytes = new byte[basicHeaderSize];
readFully(in, basicHeaderBytes);
final long basicHeaderCrc32 = read32(in) & 0xFFFFFFFFL;
final CRC32 crc32 = new CRC32();
crc32
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>.dateTimeCreated = read32(firstHeader);
localFileHeader.originalSizeEvenForVolumes = read32(firstHeader);
pushedBackBytes(12);
}
pushedBackBytes(4);
}
}
/**
* Checks if the signature matches what is expected for an arj file.
*
* @param signature
* the bytes to check
* @param length
* the number of bytes to check
* @return true, if this stream is an arj archive stream, false otherwise
*/
public static boolean matches(final byte[] signature, final int length) {
return length >= 2 &&
(0xff & signature[0]) == ARJ_MAGIC_1 &&
(0xff & signature[1]) == ARJ_MAGIC_2;
}
/**
* Gets the archive's recorded name.
* @return the archive's name
*/
public String getArchiveName() {
return mainHeader.name;
}
/**
* Gets the archive's comment.
* @return the archive's comment
*/
public String getArchiveComment() {
return mainHeader.comment;
}
@Override
public ArjArchiveEntry getNextEntry() throws IOException {
if (currentInputStream != null) {
// return value ignored as IOUtils.skip ensures the stream is drained completely
IOUtils.skip(currentInputStream, Long.MAX_VALUE);
currentInputStream.close();
currentLocalFileHeader = null;
currentInputStream = null;
}
currentLocalFileHeader = readLocalFileHeader();
if (currentLocalFileHeader != null) {
currentInputStream = new BoundedInputStream(in, currentLocalFileHeader.compressedSize);
if (currentLocalFileHeader.method == LocalFileHeader.Methods.STORED) {
currentInputStream = new CRC32VerifyingInputStream(currentInputStream,
currentLocalFileHeader.originalSize, currentLocalFileHeader.originalCrc32);
}
return new ArjArchiveEntry(currentLocalFileHeader);
}
currentInputStream = null;
return null;
}
@Override
public boolean canReadEntryData(final ArchiveEntry ae) {
return ae instanceof ArjArchiveEntry
&& ((ArjArchiveEntry) ae).getMethod() == LocalFileHeader.Methods.STORED;
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
if (currentLocalFileHeader == null) {
throw new IllegalStateException("No current arj entry");
}
if (currentLocalFileHeader.method != LocalFileHeader.Methods.STORED) {
throw new IOException("Unsupported compression method " + currentLocalFileHeader.method);
}
return currentInputStream.read(b, off, len);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> & BYTE_3_MASK) >> BYTE_3_SHIFT);
}
public void putLong(final byte[] buf, final int offset) {
putLong(value, buf, offset);
}
/**
* Helper method to get the value as a Java long from four bytes starting at given array offset
* @param bytes the array of bytes
* @param offset the offset to start
* @return the corresponding Java long value
*/
public static long getValue(final byte[] bytes, final int offset) {
long value = (bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK;
value += (bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK;
value += (bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK;
value += (bytes[offset] & BYTE_MASK);
return value;
}
/**
* Helper method to get the value as a Java long from a four-byte array
* @param bytes the array of bytes
* @return the corresponding Java long value
*/
public static long getValue(final byte[] bytes) {
return getValue(bytes, 0);
}
/**
* Override to make two instances with same value equal.
* @param o an object to compare
* @return true if the objects are equal
*/
@Override
public boolean equals(final Object o) {
if (o == null || !(o instanceof ZipLong)) {
return false;
}
return value == ((ZipLong) o).getValue();
}
/**
* Override to make two instances with same value equal.
* @return the value stored in the ZipLong
*/
@Override
public int hashCode() {
return (int) value;
}
@Override
public Object clone() {
try {
return super.clone();
} catch (final CloneNotSupportedException cnfe) {
// impossible
throw new RuntimeException(cnfe);
}
}
@Override
public String toString() {
return "ZipLong value: " + value;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.commons.compress.archivers.zip;
/**
* Info-ZIP Unicode Comment Extra Field (0x6375):
*
* <p>Stores the UTF-8 version of the file comment as stored in the
* central directory header.</p>
*
* @see <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE
* APPNOTE.TXT, section 4.6.8</a>
*
* @NotThreadSafe super-class is not thread-safe
*/
public class UnicodeCommentExtraField extends AbstractUnicodeExtraField {
public static final ZipShort UCOM_ID = new ZipShort(0x6375);
public UnicodeCommentExtraField () {
}
/**
* Assemble as unicode comment extension from the name given as
* text as well as the encoded bytes actually written to the archive.
*
* @param text The file name
* @param bytes the bytes actually written to the archive
* @param off The offset of the encoded comment in <code>bytes</code>.
* @param len The length of the encoded comment or comment in
* <code>bytes</code>.
*/
public UnicodeCommentExtraField(final String text, final byte[] bytes, final int off,
final int len) {
super(text, bytes, off, len);
}
/**
* Assemble as unicode comment extension from the comment given as
* text as well as the bytes actually written to the archive.
*
* @param comment The file comment
* @param bytes the bytes actually written to the archive
*/
public UnicodeCommentExtraField(final String comment, final byte[] bytes) {
super(comment, bytes);
}
@Override
public ZipShort getHeaderId() {
return UCOM_ID;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> {
out.write('\n'); // Pad byte
}
haveUnclosedEntry = false;
}
@Override
public void putArchiveEntry( final ArchiveEntry pEntry ) throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
final ArArchiveEntry pArEntry = (ArArchiveEntry)pEntry;
if (prevEntry == null) {
writeArchiveHeader();
} else {
if (prevEntry.getLength() != entryOffset) {
throw new IOException("length does not match entry (" + prevEntry.getLength() + " != " + entryOffset);
}
if (haveUnclosedEntry) {
closeArchiveEntry();
}
}
prevEntry = pArEntry;
writeEntryHeader(pArEntry);
entryOffset = 0;
haveUnclosedEntry = true;
}
private long fill( final long pOffset, final long pNewOffset, final char pFill ) throws IOException {
final long diff = pNewOffset - pOffset;
if (diff > 0) {
for (int i = 0; i < diff; i++) {
write(pFill);
}
}
return pNewOffset;
}
private long write( final String data ) throws IOException {
final byte[] bytes = data.getBytes("ascii");
write(bytes);
return bytes.length;
}
private long writeEntryHeader( final ArArchiveEntry pEntry ) throws IOException {
long offset = 0;
boolean mustAppendName = false;
final String n = pEntry.getName();
if (LONGFILE_ERROR == longFileMode && n.length() > 16) {
throw new IOException("filename too long, > 16 chars: "+n);
}
if (LONGFILE_BSD == longFileMode &&
(n.length() > 16 || n.contains(" "))) {
mustAppendName = true;
offset += write(ArArchiveInputStream.BSD_LONGNAME_PREFIX
+ String.valueOf(n.length()));
} else {
offset += write(n);
}
offset = fill(offset, 16, ' ');
final String m = "" + pEntry.getLastModified();
if (m.length() > 12) {
throw new IOException("modified too long");
}
offset += write(m);
offset = fill(offset, 28, ' ');
final String u = "" + pEntry.getUserId();
if (u.length() > 6) {
throw new IOException("userid too long");
}
offset += write(u);
offset = fill(offset, 34, ' ');
final String g = "" + pEntry.getGroupId();
if (g.length() > 6) {
throw new IOException("groupid too long");
}
offset += write(g);
offset = fill(offset, 40, ' ');
final String fm = "" + Integer.toString(pEntry.getMode(), 8);
if (fm
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>.length() > 8) {
throw new IOException("filemode too long");
}
offset += write(fm);
offset = fill(offset, 48, ' ');
final String s =
String.valueOf(pEntry.getLength()
+ (mustAppendName ? n.length() : 0));
if (s.length() > 10) {
throw new IOException("size too long");
}
offset += write(s);
offset = fill(offset, 58, ' ');
offset += write(ArArchiveEntry.TRAILER);
if (mustAppendName) {
offset += write(n);
}
return offset;
}
@Override
public void write(final byte[] b, final int off, final int len) throws IOException {
out.write(b, off, len);
count(len);
entryOffset += len;
}
/**
* Calls finish if necessary, and then closes the OutputStream
*/
@Override
public void close() throws IOException {
if(!finished) {
finish();
}
out.close();
prevEntry = null;
}
@Override
public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName)
throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
return new ArArchiveEntry(inputFile, entryName);
}
@Override
public void finish() throws IOException {
if(haveUnclosedEntry) {
throw new IOException("This archive contains unclosed entries.");
} else if(finished) {
throw new IOException("This archive has already been finished");
}
finished = true;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.commons.compress.archivers.zip;
import java.util.zip.ZipException;
/**
* Exception thrown when attempting to write data that requires Zip64
* support to an archive and {@link ZipArchiveOutputStream#setUseZip64
* UseZip64} has been set to {@link Zip64Mode#Never Never}.
* @since 1.3
*/
public class Zip64RequiredException extends ZipException {
private static final long serialVersionUID = 20110809L;
/**
* Helper to format "entry too big" messages.
*/
static String getEntryTooBigMessage(final ZipArchiveEntry ze) {
return ze.getName() + "'s size exceeds the limit of 4GByte.";
}
static final String ARCHIVE_TOO_BIG_MESSAGE =
"archive's size exceeds the limit of 4GByte.";
static final String TOO_MANY_ENTRIES_MESSAGE =
"archive contains more than 65535 entries.";
public Zip64RequiredException(final String reason) {
super(reason);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* This package is based on the work done by Timothy Gerard Endres
* (time@ice.com) to whom the Ant project is very grateful for his great code.
*/
package org.apache.commons.compress.archivers.tar;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipEncoding;
import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
import org.apache.commons.compress.utils.ArchiveUtils;
import org.apache.commons.compress.utils.CharsetNames;
import org.apache.commons.compress.utils.IOUtils;
/**
* The TarInputStream reads a UNIX tar archive as an InputStream.
* methods are provided to position at each successive entry in
* the archive, and the read each entry as a normal input stream
* using read().
* @NotThreadSafe
*/
public class TarArchiveInputStream extends ArchiveInputStream {
private static final int SMALL_BUFFER_SIZE = 256;
private final byte[] SMALL_BUF = new byte[SMALL_BUFFER_SIZE];
/** The size the TAR header */
private final int recordSize;
/** The size of a block */
private final int blockSize;
/** True if file has hit EOF */
private boolean hasHitEOF;
/** Size of the current entry */
private long entrySize;
/** How far into the entry the stream is at */
private long entryOffset;
/** An input stream to read from */
private final InputStream is;
/** The meta-data about the current entry */
private TarArchiveEntry currEntry;
/** The encoding of the file */
private final ZipEncoding zipEncoding;
// the provided encoding (for unit tests)
final String encoding;
// the global PAX header
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
private Map<String, String> globalPaxHeaders = new HashMap<>();
/**
* Constructor for TarInputStream.
* @param is the input stream to use
*/
public TarArchiveInputStream(final InputStream is) {
this(is, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE);
}
/**
* Constructor for TarInputStream.
* @param is the input stream to use
* @param encoding name of the encoding to use for file names
* @since 1.4
*/
public TarArchiveInputStream(final InputStream is, final String encoding) {
this(is, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE,
encoding);
}
/**
* Constructor for TarInputStream.
* @param is the input stream to use
* @param blockSize the block size to use
*/
public TarArchiveInputStream(final InputStream is, final int blockSize) {
this(is, blockSize, TarConstants.DEFAULT_RCDSIZE);
}
/**
* Constructor for TarInputStream.
* @param is the input stream to use
* @param blockSize the block size to use
* @param encoding name of the encoding to use for file names
* @since 1.4
*/
public TarArchiveInputStream(final InputStream is, final int blockSize,
final String encoding) {
this(is, blockSize, TarConstants.DEFAULT_RCDSIZE, encoding);
}
/**
* Constructor for TarInputStream.
* @param is the input stream to use
* @param blockSize the block size to use
* @param recordSize the record size to use
*/
public TarArchiveInputStream(final InputStream is, final int blockSize, final int recordSize) {
this(is, blockSize, recordSize, null);
}
/**
* Constructor for TarInputStream.
* @param is the input stream to use
* @param blockSize the block size to use
* @param recordSize the record size to use
* @param encoding name of the encoding to use for file names
* @since 1.4
*/
public TarArchiveInputStream(final InputStream is, final int blockSize, final int recordSize,
final String encoding) {
this.is = is;
this.hasHitEOF = false;
this.encoding = encoding;
this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
this.recordSize = recordSize;
this.blockSize = blockSize;
}
/**
* Closes this stream. Calls the TarBuffer's close() method.
* @throws IOException on error
*/
@Override
public void close() throws IOException {
is.close();
}
/**
* Get the record size being used by this stream's buffer.
*
* @return The TarBuffer record size.
*/
public int getRecordSize() {
return recordSize;
}
/**
* Get the available data that can be read from the current
* entry in the archive. This does not indicate how much data
* is left in the entire archive, only in the current
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>() throws IOException {
globalPaxHeaders = parsePaxHeaders(this);
getNextEntry(); // Get the actual file entry
}
private void paxHeaders() throws IOException{
final Map<String, String> headers = parsePaxHeaders(this);
getNextEntry(); // Get the actual file entry
applyPaxHeadersToCurrentEntry(headers);
}
// NOTE, using a Map here makes it impossible to ever support GNU
// sparse files using the PAX Format 0.0, see
// https://www.gnu.org/software/tar/manual/html_section/tar_92.html#SEC188
Map<String, String> parsePaxHeaders(final InputStream i)
throws IOException {
final Map<String, String> headers = new HashMap<>(globalPaxHeaders);
// Format is "length keyword=value\n";
while(true){ // get length
int ch;
int len = 0;
int read = 0;
while((ch = i.read()) != -1) {
read++;
if (ch == '\n') { // blank line in header
break;
} else if (ch == ' '){ // End of length string
// Get keyword
final ByteArrayOutputStream coll = new ByteArrayOutputStream();
while((ch = i.read()) != -1) {
read++;
if (ch == '='){ // end of keyword
final String keyword = coll.toString(CharsetNames.UTF_8);
// Get rest of entry
final int restLen = len - read;
if (restLen == 1) { // only NL
headers.remove(keyword);
} else {
final byte[] rest = new byte[restLen];
final int got = IOUtils.readFully(i, rest);
if (got != restLen) {
throw new IOException("Failed to read "
+ "Paxheader. Expected "
+ restLen
+ " bytes, read "
+ got);
}
// Drop trailing NL
final String value = new String(rest, 0,
restLen - 1, CharsetNames.UTF_8);
headers.put(keyword, value);
}
break;
}
coll.write((byte) ch);
}
break; // Processed single header
}
len *= 10;
len += ch - '0';
}
if (ch == -1){ // EOF
break;
}
}
return headers;
}
private void applyPaxHeadersToCurrentEntry(final Map<String, String> headers) {
/*
* The following headers are defined for Pax.
* atime, ctime, charset: cannot use these without changing TarArchiveEntry fields
* mtime
* comment
* gid, gname
* linkpath
* size
* uid,uname
* SCHILY.devminor, SCHILY.devmajor: don't have setters/getters for those
*
* GNU sparse files use additional members, we use
* GNU.sparse.size to detect
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> the 0.0 and 0.1 versions and
* GNU.sparse.realsize for 1.0.
*
* star files use additional members of which we use
* SCHILY.filetype in order to detect star sparse files.
*/
for (final Entry<String, String> ent : headers.entrySet()){
final String key = ent.getKey();
final String val = ent.getValue();
if ("path".equals(key)){
currEntry.setName(val);
} else if ("linkpath".equals(key)){
currEntry.setLinkName(val);
} else if ("gid".equals(key)){
currEntry.setGroupId(Long.parseLong(val));
} else if ("gname".equals(key)){
currEntry.setGroupName(val);
} else if ("uid".equals(key)){
currEntry.setUserId(Long.parseLong(val));
} else if ("uname".equals(key)){
currEntry.setUserName(val);
} else if ("size".equals(key)){
currEntry.setSize(Long.parseLong(val));
} else if ("mtime".equals(key)){
currEntry.setModTime((long) (Double.parseDouble(val) * 1000));
} else if ("SCHILY.devminor".equals(key)){
currEntry.setDevMinor(Integer.parseInt(val));
} else if ("SCHILY.devmajor".equals(key)){
currEntry.setDevMajor(Integer.parseInt(val));
} else if ("GNU.sparse.size".equals(key)) {
currEntry.fillGNUSparse0xData(headers);
} else if ("GNU.sparse.realsize".equals(key)) {
currEntry.fillGNUSparse1xData(headers);
} else if ("SCHILY.filetype".equals(key) && "sparse".equals(val)) {
currEntry.fillStarSparseData(headers);
}
}
}
/**
* Adds the sparse chunks from the current entry to the sparse chunks,
* including any additional sparse entries following the current entry.
*
* @throws IOException on error
*
* @todo Sparse files get not yet really processed.
*/
private void readOldGNUSparse() throws IOException {
/* we do not really process sparse files yet
sparses = new ArrayList();
sparses.addAll(currEntry.getSparses());
*/
if (currEntry.isExtended()) {
TarArchiveSparseEntry entry;
do {
final byte[] headerBuf = getRecord();
if (headerBuf == null) {
currEntry = null;
break;
}
entry = new TarArchiveSparseEntry(headerBuf);
/* we do not really process sparse files yet
sparses.addAll(entry.getSparses());
*/
} while (entry.isExtended());
}
}
private boolean isDirectory() {
return currEntry != null && currEntry.isDirectory();
}
/**
*
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> concrete class");
} catch (final IllegalAccessException ie) {
throw new RuntimeException(c + "\'s no-arg constructor is not public");
}
}
/**
* Create an instance of the appropriate ExtraField, falls back to
* {@link UnrecognizedExtraField UnrecognizedExtraField}.
* @param headerId the header identifier
* @return an instance of the appropriate ExtraField
* @throws InstantiationException if unable to instantiate the class
* @throws IllegalAccessException if not allowed to instantiate the class
*/
public static ZipExtraField createExtraField(final ZipShort headerId)
throws InstantiationException, IllegalAccessException {
final Class<?> c = implementations.get(headerId);
if (c != null) {
return (ZipExtraField) c.newInstance();
}
final UnrecognizedExtraField u = new UnrecognizedExtraField();
u.setHeaderId(headerId);
return u;
}
/**
* Split the array into ExtraFields and populate them with the
* given data as local file data, throwing an exception if the
* data cannot be parsed.
* @param data an array of bytes as it appears in local file data
* @return an array of ExtraFields
* @throws ZipException on error
*/
public static ZipExtraField[] parse(final byte[] data) throws ZipException {
return parse(data, true, UnparseableExtraField.THROW);
}
/**
* Split the array into ExtraFields and populate them with the
* given data, throwing an exception if the data cannot be parsed.
* @param data an array of bytes
* @param local whether data originates from the local file data
* or the central directory
* @return an array of ExtraFields
* @throws ZipException on error
*/
public static ZipExtraField[] parse(final byte[] data, final boolean local)
throws ZipException {
return parse(data, local, UnparseableExtraField.THROW);
}
/**
* Split the array into ExtraFields and populate them with the
* given data.
* @param data an array of bytes
* @param local whether data originates from the local file data
* or the central directory
* @param onUnparseableData what to do if the extra field data
* cannot be parsed.
* @return an array of ExtraFields
* @throws ZipException on error
*
* @since 1.1
*/
public static ZipExtraField[] parse(final byte[] data, final boolean local,
final UnparseableExtraField onUnparseableData)
throws ZipException {
final List<ZipExtraField> v = new ArrayList<>();
int start = 0;
LOOP:
while (start <= data.length - WORD) {
final ZipShort headerId = new ZipShort(data, start);
final int length = new ZipShort(data, start + 2).getValue();
if (start + WORD + length > data.length) {
switch(onUnparseableData.getKey()) {
case UnparseableExtraField.THROW_KEY:
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
throw new ZipException("bad extra field starting at "
+ start + ". Block length of "
+ length + " bytes exceeds remaining"
+ " data of "
+ (data.length - start - WORD)
+ " bytes.");
case UnparseableExtraField.READ_KEY:
final UnparseableExtraFieldData field =
new UnparseableExtraFieldData();
if (local) {
field.parseFromLocalFileData(data, start,
data.length - start);
} else {
field.parseFromCentralDirectoryData(data, start,
data.length - start);
}
v.add(field);
//$FALL-THROUGH$
case UnparseableExtraField.SKIP_KEY:
// since we cannot parse the data we must assume
// the extra field consumes the whole rest of the
// available data
break LOOP;
default:
throw new ZipException("unknown UnparseableExtraField key: "
+ onUnparseableData.getKey());
}
}
try {
final ZipExtraField ze = createExtraField(headerId);
if (local) {
ze.parseFromLocalFileData(data, start + WORD, length);
} else {
ze.parseFromCentralDirectoryData(data, start + WORD,
length);
}
v.add(ze);
} catch (final InstantiationException | IllegalAccessException ie) {
throw (ZipException) new ZipException(ie.getMessage()).initCause(ie);
}
start += length + WORD;
}
final ZipExtraField[] result = new ZipExtraField[v.size()];
return v.toArray(result);
}
/**
* Merges the local file data fields of the given ZipExtraFields.
* @param data an array of ExtraFiles
* @return an array of bytes
*/
public static byte[] mergeLocalFileDataData(final ZipExtraField[] data) {
final boolean lastIsUnparseableHolder = data.length > 0
&& data[data.length - 1] instanceof UnparseableExtraFieldData;
final int regularExtraFieldCount =
lastIsUnparseableHolder ? data.length - 1 : data.length;
int sum = WORD * regularExtraFieldCount;
for (final ZipExtraField element : data) {
sum += element.getLocalFileDataLength().getValue();
}
final byte[] result = new byte[sum];
int start = 0;
for (int i = 0; i < regularExtraFieldCount; i++) {
System.arraycopy(data[i].getHeaderId().getBytes(),
0, result, start, 2);
System.arraycopy(data[i].getLocalFileDataLength().getBytes(),
0, result, start + 2, 2);
start += WORD;
final byte[] local = data[i].getLocalFileDataData();
if (local != null) {
System.arraycopy(local, 0, result, start, local.length);
start += local.length;
}
}
if (
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
}
/**
* Override to make two instances with same value equal.
* @param o an object to compare
* @return true if the objects are equal
*/
@Override
public boolean equals(final Object o) {
if (o == null || !(o instanceof ZipEightByteInteger)) {
return false;
}
return value.equals(((ZipEightByteInteger) o).getValue());
}
/**
* Override to make two instances with same value equal.
* @return the hashCode of the value stored in the ZipEightByteInteger
*/
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public String toString() {
return "ZipEightByteInteger value: " + value;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers;
/**
* Archiver related Exception
*/
public class ArchiveException extends Exception {
/** Serial */
private static final long serialVersionUID = 2772690708123267100L;
/**
* Constructs a new exception with the specified detail message. The cause
* is not initialized.
*
* @param message
* the detail message
*/
public ArchiveException(final String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message
* the detail message
* @param cause
* the cause
*/
public ArchiveException(final String message, final Exception cause) {
super(message);
this.initCause(cause);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> Technology into Your Product" for more
* information.</b></p>
*
* @NotThreadSafe
* @since 1.11
*/
public class X0017_StrongEncryptionHeader extends PKWareExtraHeader {
public X0017_StrongEncryptionHeader() {
super(new ZipShort(0x0017));
}
private int format; // TODO written but not read
private EncryptionAlgorithm algId;
private int bitlen; // TODO written but not read
private int flags; // TODO written but not read
private long rcount;
private HashAlgorithm hashAlg;
private int hashSize;
// encryption data
private byte ivData[];
private byte erdData[];
// encryption key
private byte recipientKeyHash[];
private byte keyBlob[];
// password verification data
private byte vData[];
private byte vCRC32[];
/**
* Get record count.
* @return the record count
*/
public long getRecordCount() {
return rcount;
}
/**
* Get hash algorithm.
* @return the hash algorithm
*/
public HashAlgorithm getHashAlgorithm() {
return hashAlg;
}
/**
* Get encryption algorithm.
* @return the encryption algorithm
*/
public EncryptionAlgorithm getEncryptionAlgorithm() {
return algId;
}
/**
* Parse central directory format.
*
* @param data the buffer to read data from
* @param offset offset into buffer to read data
* @param length the length of data
*/
public void parseCentralDirectoryFormat(final byte[] data, final int offset, final int length) {
this.format = ZipShort.getValue(data, offset);
this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2));
this.bitlen = ZipShort.getValue(data, offset + 4);
this.flags = ZipShort.getValue(data, offset + 6);
this.rcount = ZipLong.getValue(data, offset + 8);
if (rcount > 0) {
this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 12));
this.hashSize = ZipShort.getValue(data, offset + 14);
// srlist... hashed public keys
for (int i = 0; i < this.rcount; i++) {
for (int j = 0; j < this.hashSize; j++) {
// ZipUtil.signedByteToUnsignedInt(data[offset + 16 + (i * this.hashSize) + j]));
}
}
}
}
/**
* Parse file header format.
*
* <p>(Password only?)</p>
*
* @param data the buffer to read data from
* @param offset offset into buffer to read data
* @param length the length of data
*/
public void parseFileFormat(final byte[] data, final int offset, final int length)
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> {
final int ivSize = ZipShort.getValue(data, offset);
this.ivData = new byte[ivSize];
System.arraycopy(data, offset + 4, this.ivData, 0, ivSize);
this.format = ZipShort.getValue(data, offset + ivSize + 6);
this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 8));
this.bitlen = ZipShort.getValue(data, offset + ivSize + 10);
this.flags = ZipShort.getValue(data, offset + ivSize + 12);
final int erdSize = ZipShort.getValue(data, offset + ivSize + 14);
this.erdData = new byte[erdSize];
System.arraycopy(data, offset + ivSize + 16, this.erdData, 0, erdSize);
this.rcount = ZipLong.getValue(data, offset + ivSize + 16 + erdSize);
System.out.println("rcount: " + rcount);
if (rcount == 0) {
final int vSize = ZipShort.getValue(data, offset + ivSize + 20 + erdSize);
this.vData = new byte[vSize - 4];
this.vCRC32 = new byte[4];
System.arraycopy(data, offset + ivSize + 22 + erdSize , this.vData, 0, vSize - 4);
System.arraycopy(data, offset + ivSize + 22 + erdSize + vSize - 4, vCRC32, 0, 4);
} else {
this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 20 + erdSize));
this.hashSize = ZipShort.getValue(data, offset + ivSize + 22 + erdSize);
final int resize = ZipShort.getValue(data, offset + ivSize + 24 + erdSize);
this.recipientKeyHash = new byte[this.hashSize];
this.keyBlob = new byte[resize - this.hashSize];
System.arraycopy(data, offset + ivSize + 24 + erdSize, this.recipientKeyHash, 0, this.hashSize);
System.arraycopy(data, offset + ivSize + 24 + erdSize + this.hashSize, this.keyBlob, 0, resize - this.hashSize);
final int vSize = ZipShort.getValue(data, offset + ivSize + 26 + erdSize + resize);
this.vData = new byte[vSize - 4];
this.vCRC32 = new byte[4];
System.arraycopy(data, offset + ivSize + 22 + erdSize + resize, this.vData, 0, vSize - 4);
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.cpio;
/**
* All constants needed by CPIO.
*
* based on code from the jRPM project (jrpm.sourceforge.net)
*
*/
public interface CpioConstants {
/** magic number of a cpio entry in the new format */
String MAGIC_NEW = "070701";
/** magic number of a cpio entry in the new format with crc */
String MAGIC_NEW_CRC = "070702";
/** magic number of a cpio entry in the old ascii format */
String MAGIC_OLD_ASCII = "070707";
/** magic number of a cpio entry in the old binary format */
int MAGIC_OLD_BINARY = 070707;
// These FORMAT_ constants are internal to the code
/** write/read a CPIOArchiveEntry in the new format */
short FORMAT_NEW = 1;
/** write/read a CPIOArchiveEntry in the new format with crc */
short FORMAT_NEW_CRC = 2;
/** write/read a CPIOArchiveEntry in the old ascii format */
short FORMAT_OLD_ASCII = 4;
/** write/read a CPIOArchiveEntry in the old binary format */
short FORMAT_OLD_BINARY = 8;
/** Mask for both new formats */
short FORMAT_NEW_MASK = 3;
/** Mask for both old formats */
short FORMAT_OLD_MASK = 12;
/*
* Constants for the MODE bits
*/
/** Mask for all file type bits. */
int S_IFMT = 0170000;
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/cpio.h.html
// has a list of the C_xxx constatnts
/** Defines a socket */
int C_ISSOCK = 0140000;
/** Defines a symbolic link */
int C_ISLNK = 0120000;
/** HP/UX network special (C_
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>ISCTG) */
int C_ISNWK = 0110000;
/** Defines a regular file */
int C_ISREG = 0100000;
/** Defines a block device */
int C_ISBLK = 0060000;
/** Defines a directory */
int C_ISDIR = 0040000;
/** Defines a character device */
int C_ISCHR = 0020000;
/** Defines a pipe */
int C_ISFIFO = 0010000;
/** Set user ID */
int C_ISUID = 0004000;
/** Set group ID */
int C_ISGID = 0002000;
/** On directories, restricted deletion flag. */
int C_ISVTX = 0001000;
/** Permits the owner of a file to read the file */
int C_IRUSR = 0000400;
/** Permits the owner of a file to write to the file */
int C_IWUSR = 0000200;
/** Permits the owner of a file to execute the file or to search the directory */
int C_IXUSR = 0000100;
/** Permits a file's group to read the file */
int C_IRGRP = 0000040;
/** Permits a file's group to write to the file */
int C_IWGRP = 0000020;
/** Permits a file's group to execute the file or to search the directory */
int C_IXGRP = 0000010;
/** Permits others to read the file */
int C_IROTH = 0000004;
/** Permits others to write to the file */
int C_IWOTH = 0000002;
/** Permits others to execute the file or to search the directory */
int C_IXOTH = 0000001;
/** The special trailer marker */
String CPIO_TRAILER = "TRAILER!!!";
/**
* The default block size.
*
* @since 1.1
*/
int BLOCK_SIZE = 512;
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.commons.compress.archivers.zip;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.compress.utils.Charsets;
/**
* Static helper functions for robustly encoding filenames in zip files.
*/
public abstract class ZipEncodingHelper {
/**
* A class, which holds the high characters of a simple encoding
* and lazily instantiates a Simple8BitZipEncoding instance in a
* thread-safe manner.
*/
private static class SimpleEncodingHolder {
private final char [] highChars;
private Simple8BitZipEncoding encoding;
/**
* Instantiate a simple encoding holder.
*
* @param highChars The characters for byte codes 128 to 255.
*
* @see Simple8BitZipEncoding#Simple8BitZipEncoding(char[])
*/
SimpleEncodingHolder(final char [] highChars) {
this.highChars = highChars;
}
/**
* @return The associated {@link Simple8BitZipEncoding}, which
* is instantiated if not done so far.
*/
public synchronized Simple8BitZipEncoding getEncoding() {
if (this.encoding == null) {
this.encoding = new Simple8BitZipEncoding(this.highChars);
}
return this.encoding;
}
}
private static final Map<String, SimpleEncodingHolder> simpleEncodings;
static {
final Map<String, SimpleEncodingHolder> se =
new HashMap<>();
final char[] cp437_high_chars =
new char[] { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0,
0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x0
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
static final String UTF8 = "UTF8";
/**
* name of the encoding UTF-8
*/
static final ZipEncoding UTF8_ZIP_ENCODING = new FallbackZipEncoding(UTF8);
/**
* Instantiates a zip encoding.
*
* @param name The name of the zip encoding. Specify {@code null} for
* the platform's default encoding.
* @return A zip encoding for the given encoding name.
*/
public static ZipEncoding getZipEncoding(final String name) {
// fallback encoding is good enough for UTF-8.
if (isUTF8(name)) {
return UTF8_ZIP_ENCODING;
}
if (name == null) {
return new FallbackZipEncoding();
}
final SimpleEncodingHolder h = simpleEncodings.get(name);
if (h!=null) {
return h.getEncoding();
}
try {
final Charset cs = Charset.forName(name);
return new NioZipEncoding(cs);
} catch (final UnsupportedCharsetException e) {
return new FallbackZipEncoding(name);
}
}
/**
* Returns whether a given encoding is UTF-8. If the given name is null, then check the platform's default encoding.
*
* @param charsetName
* If the given name is null, then check the platform's default encoding.
*/
static boolean isUTF8(String charsetName) {
if (charsetName == null) {
// check platform's default encoding
charsetName = Charset.defaultCharset().name();
}
if (Charsets.UTF_8.name().equalsIgnoreCase(charsetName)) {
return true;
}
for (final String alias : Charsets.UTF_8.aliases()) {
if (alias.equalsIgnoreCase(charsetName)) {
return true;
}
}
return false;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>20;
private static final int CFH_ORIGINAL_SIZE_OFFSET = 24;
private static final int CFH_FILENAME_LENGTH_OFFSET = 28;
private static final int CFH_EXTRA_LENGTH_OFFSET = 30;
private static final int CFH_COMMENT_LENGTH_OFFSET = 32;
private static final int CFH_DISK_NUMBER_OFFSET = 34;
private static final int CFH_INTERNAL_ATTRIBUTES_OFFSET = 36;
private static final int CFH_EXTERNAL_ATTRIBUTES_OFFSET = 38;
private static final int CFH_LFH_OFFSET = 42;
private static final int CFH_FILENAME_OFFSET = 46;
/** indicates if this archive is finished. protected for use in Jar implementation */
protected boolean finished = false;
/**
* Compression method for deflated entries.
*/
public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED;
/**
* Default compression level for deflated entries.
*/
public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION;
/**
* Compression method for stored entries.
*/
public static final int STORED = java.util.zip.ZipEntry.STORED;
/**
* default encoding for file names and comment.
*/
static final String DEFAULT_ENCODING = ZipEncodingHelper.UTF8;
/**
* General purpose flag, which indicates that filenames are
* written in UTF-8.
* @deprecated use {@link GeneralPurposeBit#UFT8_NAMES_FLAG} instead
*/
@Deprecated
public static final int EFS_FLAG = GeneralPurposeBit.UFT8_NAMES_FLAG;
private static final byte[] EMPTY = new byte[0];
/**
* Current entry.
*/
private CurrentEntry entry;
/**
* The file comment.
*/
private String comment = "";
/**
* Compression level for next entry.
*/
private int level = DEFAULT_COMPRESSION;
/**
* Has the compression level changed when compared to the last
* entry?
*/
private boolean hasCompressionLevelChanged = false;
/**
* Default compression method for next entry.
*/
private int method = java.util.zip.ZipEntry.DEFLATED;
/**
* List of ZipArchiveEntries written so far.
*/
private final List<ZipArchiveEntry> entries =
new LinkedList<>();
private final StreamCompressor streamCompressor;
/**
* Start of central directory.
*/
private long cdOffset = 0;
/**
* Length of central directory.
*/
private long cdLength = 0;
/**
* Helper, a 0 as ZipShort.
*/
private static final byte[] ZERO = {0, 0};
/**
* Helper, a 0 as ZipLong.
*/
private static final byte[] LZERO = {0, 0, 0, 0};
private static final byte[] ONE = ZipLong.getBytes(1L);
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> /**
* Holds the offsets of the LFH starts for each entry.
*/
private final Map<ZipArchiveEntry, Long> offsets =
new HashMap<>();
/**
* The encoding to use for filenames and the file comment.
*
* <p>For a list of possible values see <a
* href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
* Defaults to UTF-8.</p>
*/
private String encoding = DEFAULT_ENCODING;
/**
* The zip encoding to use for filenames and the file comment.
*
* This field is of internal use and will be set in {@link
* #setEncoding(String)}.
*/
private ZipEncoding zipEncoding =
ZipEncodingHelper.getZipEncoding(DEFAULT_ENCODING);
/**
* This Deflater object is used for output.
*
*/
protected final Deflater def;
/**
* Optional random access output.
*/
private final SeekableByteChannel channel;
private final OutputStream out;
/**
* whether to use the general purpose bit flag when writing UTF-8
* filenames or not.
*/
private boolean useUTF8Flag = true;
/**
* Whether to encode non-encodable file names as UTF-8.
*/
private boolean fallbackToUTF8 = false;
/**
* whether to create UnicodePathExtraField-s for each entry.
*/
private UnicodeExtraFieldPolicy createUnicodeExtraFields = UnicodeExtraFieldPolicy.NEVER;
/**
* Whether anything inside this archive has used a ZIP64 feature.
*
* @since 1.3
*/
private boolean hasUsedZip64 = false;
private Zip64Mode zip64Mode = Zip64Mode.AsNeeded;
private final byte[] copyBuffer = new byte[32768];
private final Calendar calendarInstance = Calendar.getInstance();
/**
* Creates a new ZIP OutputStream filtering the underlying stream.
* @param out the outputstream to zip
*/
public ZipArchiveOutputStream(final OutputStream out) {
this.out = out;
this.channel = null;
def = new Deflater(level, true);
streamCompressor = StreamCompressor.create(out, def);
}
/**
* Creates a new ZIP OutputStream writing to a File. Will use
* random access if possible.
* @param file the file to zip to
* @throws IOException on error
*/
public ZipArchiveOutputStream(final File file) throws IOException {
def = new Deflater(level, true);
OutputStream o = null;
SeekableByteChannel _channel = null;
StreamCompressor _streamCompressor = null;
try {
_channel = Files.newByteChannel(file.toPath(),
EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE,
StandardOpenOption.READ,
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> StandardOpenOption.TRUNCATE_EXISTING));
_streamCompressor = StreamCompressor.create(_channel, def);
} catch (final IOException e) {
IOUtils.closeQuietly(_channel);
_channel = null;
o = new FileOutputStream(file);
_streamCompressor = StreamCompressor.create(o, def);
}
out = o;
channel = _channel;
streamCompressor = _streamCompressor;
}
/**
* Creates a new ZIP OutputStream writing to a SeekableByteChannel.
*
* <p>{@link
* org.apache.commons.compress.utils.SeekableInMemoryByteChannel}
* allows you to write to an in-memory archive using random
* access.</p>
*
* @param channel the channel to zip to
* @throws IOException on error
* @since 1.13
*/
public ZipArchiveOutputStream(SeekableByteChannel channel) throws IOException {
this.channel = channel;
def = new Deflater(level, true);
streamCompressor = StreamCompressor.create(channel, def);
out = null;
}
/**
* This method indicates whether this archive is writing to a
* seekable stream (i.e., to a random access file).
*
* <p>For seekable streams, you don't need to calculate the CRC or
* uncompressed size for {@link #STORED} entries before
* invoking {@link #putArchiveEntry(ArchiveEntry)}.
* @return true if seekable
*/
public boolean isSeekable() {
return channel != null;
}
/**
* The encoding to use for filenames and the file comment.
*
* <p>For a list of possible values see <a
* href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
* Defaults to UTF-8.</p>
* @param encoding the encoding to use for file names, use null
* for the platform's default encoding
*/
public void setEncoding(final String encoding) {
this.encoding = encoding;
this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
if (useUTF8Flag && !ZipEncodingHelper.isUTF8(encoding)) {
useUTF8Flag = false;
}
}
/**
* The encoding to use for filenames and the file comment.
*
* @return null if using the platform's default character encoding.
*/
public String getEncoding() {
return encoding;
}
/**
* Whether to set the language encoding flag if the file name
* encoding is UTF-8.
*
* <p>Defaults to true.</p>
*
* @param b whether to set the language encoding flag if the file
* name encoding is UTF-8
*/
public void setUseLanguageEncodingFlag(final boolean b) {
useUTF8
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> the stream.
*/
private void flushDeflater() throws IOException {
if (entry.entry.getMethod() == DEFLATED) {
streamCompressor.flushDeflater();
}
}
/**
* Ensures the current entry's size and CRC information is set to
* the values just written, verifies it isn't too big in the
* Zip64Mode.Never case and returns whether the entry would
* require a Zip64 extra field.
*/
private boolean handleSizesAndCrc(final long bytesWritten, final long crc,
final Zip64Mode effectiveMode)
throws ZipException {
if (entry.entry.getMethod() == DEFLATED) {
/* It turns out def.getBytesRead() returns wrong values if
* the size exceeds 4 GB on Java < Java7
entry.entry.setSize(def.getBytesRead());
*/
entry.entry.setSize(entry.bytesRead);
entry.entry.setCompressedSize(bytesWritten);
entry.entry.setCrc(crc);
} else if (channel == null) {
if (entry.entry.getCrc() != crc) {
throw new ZipException("bad CRC checksum for entry "
+ entry.entry.getName() + ": "
+ Long.toHexString(entry.entry.getCrc())
+ " instead of "
+ Long.toHexString(crc));
}
if (entry.entry.getSize() != bytesWritten) {
throw new ZipException("bad size for entry "
+ entry.entry.getName() + ": "
+ entry.entry.getSize()
+ " instead of "
+ bytesWritten);
}
} else { /* method is STORED and we used SeekableByteChannel */
entry.entry.setSize(bytesWritten);
entry.entry.setCompressedSize(bytesWritten);
entry.entry.setCrc(crc);
}
return checkIfNeedsZip64(effectiveMode);
}
/**
* Ensures the current entry's size and CRC information is set to
* the values just written, verifies it isn't too big in the
* Zip64Mode.Never case and returns whether the entry would
* require a Zip64 extra field.
*/
private boolean checkIfNeedsZip64(final Zip64Mode effectiveMode)
throws ZipException {
final boolean actuallyNeedsZip64 = isZip64Required(entry.entry, effectiveMode);
if (actuallyNeedsZip64 && effectiveMode == Zip64Mode.Never) {
throw new Zip64RequiredException(Zip64RequiredException.getEntryTooBigMessage(entry.entry));
}
return actuallyNeedsZip64;
}
private boolean isZip64Required(final ZipArchiveEntry entry1, final Zip64Mode requestedMode) {
return requestedMode == Zip64Mode.Always || isTooLageForZip32(entry1);
}
private boolean isTooLageForZip32(final ZipArchiveEntry zipArchiveEntry){
return zipArchiveEntry.getSize() >= ZIP64_MAGIC ||
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> process.
* @param archiveEntry The archiveEntry
* @param phased If true size, compressedSize and crc required to be known up-front in the archiveEntry
* @throws ClassCastException if entry is not an instance of ZipArchiveEntry
* @throws Zip64RequiredException if the entry's uncompressed or
* compressed size is known to exceed 4 GByte and {@link #setUseZip64}
* is {@link Zip64Mode#Never}.
*/
private void putArchiveEntry(final ArchiveEntry archiveEntry, final boolean phased) throws IOException {
if (finished) {
throw new IOException("Stream has already been finished");
}
if (entry != null) {
closeArchiveEntry();
}
entry = new CurrentEntry((ZipArchiveEntry) archiveEntry);
entries.add(entry.entry);
setDefaults(entry.entry);
final Zip64Mode effectiveMode = getEffectiveZip64Mode(entry.entry);
validateSizeInformation(effectiveMode);
if (shouldAddZip64Extra(entry.entry, effectiveMode)) {
final Zip64ExtendedInformationExtraField z64 = getZip64Extra(entry.entry);
// just a placeholder, real data will be in data
// descriptor or inserted later via SeekableByteChannel
ZipEightByteInteger size = ZipEightByteInteger.ZERO;
ZipEightByteInteger compressedSize = ZipEightByteInteger.ZERO;
if (phased){
size = new ZipEightByteInteger(entry.entry.getSize());
compressedSize = new ZipEightByteInteger(entry.entry.getCompressedSize());
} else if (entry.entry.getMethod() == STORED
&& entry.entry.getSize() != ArchiveEntry.SIZE_UNKNOWN) {
// actually, we already know the sizes
size = new ZipEightByteInteger(entry.entry.getSize());
compressedSize = size;
}
z64.setSize(size);
z64.setCompressedSize(compressedSize);
entry.entry.setExtra();
}
if (entry.entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {
def.setLevel(level);
hasCompressionLevelChanged = false;
}
writeLocalFileHeader((ZipArchiveEntry) archiveEntry, phased);
}
/**
* Provides default values for compression method and last
* modification time.
*/
private void setDefaults(final ZipArchiveEntry entry) {
if (entry.getMethod() == -1) { // not specified
entry.setMethod(method);
}
if (entry.getTime() == -1) { // not specified
entry.setTime(System.currentTimeMillis());
}
}
/**
* Throws an exception if the size is unknown for a stored entry
* that is written to a non-seekable output or the entry is too
* big to be written without Zip64 extra but the mode has been set
* to Never.
*/
private void validateSizeInformation(final Zip64Mode effectiveMode)
throws ZipException {
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> // Size/CRC not required if SeekableByteChannel is used
if (entry.entry.getMethod() == STORED && channel == null) {
if (entry.entry.getSize() == ArchiveEntry.SIZE_UNKNOWN) {
throw new ZipException("uncompressed size is required for"
+ " STORED method when not writing to a"
+ " file");
}
if (entry.entry.getCrc() == ZipArchiveEntry.CRC_UNKNOWN) {
throw new ZipException("crc checksum is required for STORED"
+ " method when not writing to a file");
}
entry.entry.setCompressedSize(entry.entry.getSize());
}
if ((entry.entry.getSize() >= ZIP64_MAGIC
|| entry.entry.getCompressedSize() >= ZIP64_MAGIC)
&& effectiveMode == Zip64Mode.Never) {
throw new Zip64RequiredException(Zip64RequiredException
.getEntryTooBigMessage(entry.entry));
}
}
/**
* Whether to addd a Zip64 extended information extra field to the
* local file header.
*
* <p>Returns true if</p>
*
* <ul>
* <li>mode is Always</li>
* <li>or we already know it is going to be needed</li>
* <li>or the size is unknown and we can ensure it won't hurt
* other implementations if we add it (i.e. we can erase its
* usage</li>
* </ul>
*/
private boolean shouldAddZip64Extra(final ZipArchiveEntry entry, final Zip64Mode mode) {
return mode == Zip64Mode.Always
|| entry.getSize() >= ZIP64_MAGIC
|| entry.getCompressedSize() >= ZIP64_MAGIC
|| (entry.getSize() == ArchiveEntry.SIZE_UNKNOWN
&& channel != null && mode != Zip64Mode.Never);
}
/**
* Set the file comment.
* @param comment the comment
*/
public void setComment(final String comment) {
this.comment = comment;
}
/**
* Sets the compression level for subsequent entries.
*
* <p>Default is Deflater.DEFAULT_COMPRESSION.</p>
* @param level the compression level.
* @throws IllegalArgumentException if an invalid compression
* level is specified.
*/
public void setLevel(final int level) {
if (level < Deflater.DEFAULT_COMPRESSION
|| level > Deflater.BEST_COMPRESSION) {
throw new IllegalArgumentException("Invalid compression level: "
+ level);
}
hasCompressionLevelChanged = (this.level != level);
this.level = level;
}
/**
* Sets the default compression method for subsequent entries.
*
* <p>Default is DEFLATED.</p>
* @param method an <code>int</code> from java.util.zip.ZipEntry
*/
public void setMethod(final int method) {
this.method =
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> {
ze.addExtraField(new UnicodePathExtraField(ze.getName(),
name.array(),
name.arrayOffset(),
name.limit()
- name.position()));
}
final String comm = ze.getComment();
if (comm != null && !"".equals(comm)) {
final boolean commentEncodable = zipEncoding.canEncode(comm);
if (createUnicodeExtraFields == UnicodeExtraFieldPolicy.ALWAYS
|| !commentEncodable) {
final ByteBuffer commentB = getEntryEncoding(ze).encode(comm);
ze.addExtraField(new UnicodeCommentExtraField(comm,
commentB.array(),
commentB.arrayOffset(),
commentB.limit()
- commentB.position())
);
}
}
}
/**
* Writes the data descriptor entry.
* @param ze the entry to write
* @throws IOException on error
*/
protected void writeDataDescriptor(final ZipArchiveEntry ze) throws IOException {
if (ze.getMethod() != DEFLATED || channel != null) {
return;
}
writeCounted(DD_SIG);
writeCounted(ZipLong.getBytes(ze.getCrc()));
if (!hasZip64Extra(ze)) {
writeCounted(ZipLong.getBytes(ze.getCompressedSize()));
writeCounted(ZipLong.getBytes(ze.getSize()));
} else {
writeCounted(ZipEightByteInteger.getBytes(ze.getCompressedSize()));
writeCounted(ZipEightByteInteger.getBytes(ze.getSize()));
}
}
/**
* Writes the central file header entry.
* @param ze the entry to write
* @throws IOException on error
* @throws Zip64RequiredException if the archive's size exceeds 4
* GByte and {@link Zip64Mode #setUseZip64} is {@link
* Zip64Mode#Never}.
*/
protected void writeCentralFileHeader(final ZipArchiveEntry ze) throws IOException {
final byte[] centralFileHeader = createCentralFileHeader(ze);
writeCounted(centralFileHeader);
}
private byte[] createCentralFileHeader(final ZipArchiveEntry ze) throws IOException {
final long lfhOffset = offsets.get(ze);
final boolean needsZip64Extra = hasZip64Extra(ze)
|| ze.getCompressedSize() >= ZIP64_MAGIC
|| ze.getSize() >= ZIP64_MAGIC
|| lfhOffset >= ZIP64_MAGIC
|| zip64Mode == Zip64Mode.Always;
if (needsZip64Extra && zip64Mode == Zip64Mode.Never) {
// must be the offset that is too big, otherwise an
// exception would have been throw in putArchiveEntry or
// closeArchiveEntry
throw new Zip64RequiredException(Zip64RequiredException
.ARCHIVE_TOO_BIG_MESSAGE);
}
handleZip64Extra(ze, lfhOffset, needsZip64Extra);
return createCentralFileHeader(ze
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>, getName(ze), lfhOffset, needsZip64Extra);
}
/**
* Writes the central file header entry.
* @param ze the entry to write
* @param name The encoded name
* @param lfhOffset Local file header offset for this file
* @throws IOException on error
*/
private byte[] createCentralFileHeader(final ZipArchiveEntry ze, final ByteBuffer name, final long lfhOffset,
final boolean needsZip64Extra) throws IOException {
final byte[] extra = ze.getCentralDirectoryExtra();
// file comment length
String comm = ze.getComment();
if (comm == null) {
comm = "";
}
final ByteBuffer commentB = getEntryEncoding(ze).encode(comm);
final int nameLen = name.limit() - name.position();
final int commentLen = commentB.limit() - commentB.position();
final int len= CFH_FILENAME_OFFSET + nameLen + extra.length + commentLen;
final byte[] buf = new byte[len];
System.arraycopy(CFH_SIG, 0, buf, CFH_SIG_OFFSET, WORD);
// version made by
// CheckStyle:MagicNumber OFF
putShort((ze.getPlatform() << 8) | (!hasUsedZip64 ? DATA_DESCRIPTOR_MIN_VERSION : ZIP64_MIN_VERSION),
buf, CFH_VERSION_MADE_BY_OFFSET);
final int zipMethod = ze.getMethod();
final boolean encodable = zipEncoding.canEncode(ze.getName());
putShort(versionNeededToExtract(zipMethod, needsZip64Extra), buf, CFH_VERSION_NEEDED_OFFSET);
getGeneralPurposeBits(zipMethod, !encodable && fallbackToUTF8).encode(buf, CFH_GPB_OFFSET);
// compression method
putShort(zipMethod, buf, CFH_METHOD_OFFSET);
// last mod. time and date
ZipUtil.toDosTime(calendarInstance, ze.getTime(), buf, CFH_TIME_OFFSET);
// CRC
// compressed length
// uncompressed length
putLong(ze.getCrc(), buf, CFH_CRC_OFFSET);
if (ze.getCompressedSize() >= ZIP64_MAGIC
|| ze.getSize() >= ZIP64_MAGIC
|| zip64Mode == Zip64Mode.Always) {
ZipLong.ZIP64_MAGIC.putLong(buf, CFH_COMPRESSED_SIZE_OFFSET);
ZipLong.ZIP64_MAGIC.putLong(buf, CFH_ORIGINAL_SIZE_OFFSET);
} else {
putLong(ze.getCompressedSize(), buf, CFH_COMPRESSED_SIZE_OFFSET);
putLong(ze.getSize(), buf, CFH_ORIGINAL_SIZE_OFFSET);
}
putShort(nameLen, buf, CFH_FILENAME_LENGTH_OFFSET);
// extra field length
putShort(extra.length, buf, CFH_EXTRA_LENGTH_OFFSET);
putShort(
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> writeOut(LZERO);
// number of entries
final byte[] num = ZipEightByteInteger.getBytes(entries.size());
writeOut(num);
writeOut(num);
// length and location of CD
writeOut(ZipEightByteInteger.getBytes(cdLength));
writeOut(ZipEightByteInteger.getBytes(cdOffset));
// no "zip64 extensible data sector" for now
// and now the "ZIP64 end of central directory locator"
writeOut(ZIP64_EOCD_LOC_SIG);
// disk number holding the ZIP64 EOCD record
writeOut(LZERO);
// relative offset of ZIP64 EOCD record
writeOut(ZipEightByteInteger.getBytes(offset));
// total number of disks
writeOut(ONE);
}
/**
* Write bytes to output or random access file.
* @param data the byte array to write
* @throws IOException on error
*/
protected final void writeOut(final byte[] data) throws IOException {
streamCompressor.writeOut(data, 0, data.length);
}
/**
* Write bytes to output or random access file.
* @param data the byte array to write
* @param offset the start position to write from
* @param length the number of bytes to write
* @throws IOException on error
*/
protected final void writeOut(final byte[] data, final int offset, final int length)
throws IOException {
streamCompressor.writeOut(data, offset, length);
}
private GeneralPurposeBit getGeneralPurposeBits(final int zipMethod, final boolean utfFallback) {
final GeneralPurposeBit b = new GeneralPurposeBit();
b.useUTF8ForNames(useUTF8Flag || utfFallback);
if (isDeflatedToOutputStream(zipMethod)) {
b.useDataDescriptor(true);
}
return b;
}
private int versionNeededToExtract(final int zipMethod, final boolean zip64) {
if (zip64) {
return ZIP64_MIN_VERSION;
}
// requires version 2 as we are going to store length info
// in the data descriptor
return (isDeflatedToOutputStream(zipMethod)) ?
DATA_DESCRIPTOR_MIN_VERSION :
INITIAL_VERSION;
}
private boolean isDeflatedToOutputStream(final int zipMethod) {
return zipMethod == DEFLATED && channel == null;
}
/**
* Creates a new zip entry taking some information from the given
* file and using the provided name.
*
* <p>The name will be adjusted to end with a forward slash "/" if
* the file is a directory. If the file is not a directory a
* potential trailing forward slash will be stripped from the
* entry name.</p>
*
* <p>Must not be used if the stream has already been closed.</p>
*/
@Override
public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName)
throws IOException {
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> {
if (channel != null) {
channel.close();
}
if (out != null) {
out.close();
}
}
/**
* enum that represents the possible policies for creating Unicode
* extra fields.
*/
public static final class UnicodeExtraFieldPolicy {
/**
* Always create Unicode extra fields.
*/
public static final UnicodeExtraFieldPolicy ALWAYS = new UnicodeExtraFieldPolicy("always");
/**
* Never create Unicode extra fields.
*/
public static final UnicodeExtraFieldPolicy NEVER = new UnicodeExtraFieldPolicy("never");
/**
* Create Unicode extra fields for filenames that cannot be
* encoded using the specified encoding.
*/
public static final UnicodeExtraFieldPolicy NOT_ENCODEABLE =
new UnicodeExtraFieldPolicy("not encodeable");
private final String name;
private UnicodeExtraFieldPolicy(final String n) {
name = n;
}
@Override
public String toString() {
return name;
}
}
/**
* Structure collecting information for the entry that is
* currently being written.
*/
private static final class CurrentEntry {
private CurrentEntry(final ZipArchiveEntry entry) {
this.entry = entry;
}
/**
* Current ZIP entry.
*/
private final ZipArchiveEntry entry;
/**
* Offset for CRC entry in the local file header data for the
* current entry starts here.
*/
private long localDataStart = 0;
/**
* Data for local header data
*/
private long dataStart = 0;
/**
* Number of bytes read for the current entry (can't rely on
* Deflater#getBytesRead) when using DEFLATED.
*/
private long bytesRead = 0;
/**
* Whether current entry was the first one using ZIP64 features.
*/
private boolean causedUseOfZip64 = false;
/**
* Whether write() has been called at all.
*
* <p>In order to create a valid archive {@link
* #closeArchiveEntry closeArchiveEntry} will write an empty
* array to get the CRC right if nothing has been written to
* the stream at all.</p>
*/
private boolean hasWritten;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.zip;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* An interface for encoders that do a pretty encoding of ZIP
* filenames.
*
* <p>There are mostly two implementations, one that uses java.nio
* {@link java.nio.charset.Charset Charset} and one implementation,
* which copes with simple 8 bit charsets, because java-1.4 did not
* support Cp437 in java.nio.</p>
*
* <p>The main reason for defining an own encoding layer comes from
* the problems with {@link java.lang.String#getBytes(String)
* String.getBytes}, which encodes unknown characters as ASCII
* quotation marks ('?'). Quotation marks are per definition an
* invalid filename on some operating systems like Windows, which
* leads to ignored ZIP entries.</p>
*
* <p>All implementations should implement this interface in a
* reentrant way.</p>
*/
public interface ZipEncoding {
/**
* Check, whether the given string may be losslessly encoded using this
* encoding.
*
* @param name A filename or ZIP comment.
* @return Whether the given name may be encoded with out any losses.
*/
boolean canEncode(String name);
/**
* Encode a filename or a comment to a byte array suitable for
* storing it to a serialized zip entry.
*
* <p>Examples for CP 437 (in pseudo-notation, right hand side is
* C-style notation):</p>
* <pre>
* encode("\u20AC_for_Dollar.txt") = "%U20AC_for_Dollar.txt"
* encode("\u00D6lf\u00E4sser.txt") = "\231lf\204sser.txt"
* </pre>
*
* @param name A filename or ZIP comment.
* @return A byte buffer with a backing array containing the
* encoded name. Unmappable characters or malformed
* character sequences are mapped to a sequence
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> of utf-16
* words encoded in the format <code>%Uxxxx</code>. It is
* assumed, that the byte buffer is positioned at the
* beginning of the encoded result, the byte buffer has a
* backing array and the limit of the byte buffer points
* to the end of the encoded result.
* @throws IOException on error
*/
ByteBuffer encode(String name) throws IOException;
/**
* @param data The byte values to decode.
* @return The decoded string.
* @throws IOException on error
*/
String decode(byte [] data) throws IOException;
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>() throws Exception {
try (ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("COMPRESS-264.zip")))) {
final ZipArchiveEntry ze = in.getNextZipEntry();
assertEquals(5, ze.getSize());
assertArrayEquals(new byte[] { 'd', 'a', 't', 'a', '\n' },
IOUtils.toByteArray(in));
}
}
/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/COMPRESS-351"
* >COMPRESS-351</a>.
*/
@Test
public void testMessageWithCorruptFileName() throws Exception {
try (ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("COMPRESS-351.zip")))) {
ZipArchiveEntry ze = in.getNextZipEntry();
while (ze != null) {
ze = in.getNextZipEntry();
}
fail("expected EOFException");
} catch (final EOFException ex) {
final String m = ex.getMessage();
assertTrue(m.startsWith("Truncated ZIP entry: ?2016")); // the first character is not printable
}
}
@Test
public void testUnzipBZip2CompressedEntry() throws Exception {
try (ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("bzip2-zip.zip")))) {
final ZipArchiveEntry ze = in.getNextZipEntry();
assertEquals(42, ze.getSize());
final byte[] expected = new byte[42];
Arrays.fill(expected, (byte) 'a');
assertArrayEquals(expected, IOUtils.toByteArray(in));
}
}
/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/COMPRESS-364"
* >COMPRESS-364</a>.
*/
@Test
public void testWithBytesAfterData() throws Exception {
final int expectedNumEntries = 2;
final InputStream is = ZipArchiveInputStreamTest.class
.getResourceAsStream("/archive_with_bytes_after_data.zip");
final ZipArchiveInputStream zip = new ZipArchiveInputStream(is);
try {
int actualNumEntries = 0;
ZipArchiveEntry zae = zip.getNextZipEntry();
while (zae != null) {
actualNumEntries++;
readEntry(zip, zae);
zae = zip.getNextZipEntry();
}
assertEquals(expectedNumEntries, actualNumEntries);
} finally {
zip.close();
}
}
/**
* <code>getNextZipEntry()</code> should throw a <code>ZipException</code> rather than return
* <code>null</code> when an unexpected structure is encountered.
*/
@Test
public void testThrowOnInvalidEntry() throws Exception {
final InputStream is = ZipArchiveInputStreamTest.class
.getResourceAsStream("/invalid-zip.zip");
final ZipArchiveInputStream zip = new ZipArchiveInputStream(is);
try {
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
zip.getNextZipEntry();
fail("IOException expected");
} catch (ZipException expected) {
assertTrue(expected.getMessage().contains("Unexpected record signature"));
} finally {
zip.close();
}
}
private static byte[] readEntry(ZipArchiveInputStream zip, ZipArchiveEntry zae) throws IOException {
final int len = (int)zae.getSize();
final byte[] buff = new byte[len];
zip.read(buff, 0, len);
return buff;
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.commons.compress.archivers.zip;
import java.io.UnsupportedEncodingException;
import java.util.zip.CRC32;
import java.util.zip.ZipException;
import org.apache.commons.compress.utils.CharsetNames;
/**
* A common base class for Unicode extra information extra fields.
* @NotThreadSafe
*/
public abstract class AbstractUnicodeExtraField implements ZipExtraField {
private long nameCRC32;
private byte[] unicodeName;
private byte[] data;
protected AbstractUnicodeExtraField() {
}
/**
* Assemble as unicode extension from the name/comment and
* encoding of the original zip entry.
*
* @param text The file name or comment.
* @param bytes The encoded of the filename or comment in the zip
* file.
* @param off The offset of the encoded filename or comment in
* <code>bytes</code>.
* @param len The length of the encoded filename or commentin
* <code>bytes</code>.
*/
protected AbstractUnicodeExtraField(final String text, final byte[] bytes, final int off, final int len) {
final CRC32 crc32 = new CRC32();
crc32.update(bytes, off, len);
nameCRC32 = crc32.getValue();
try {
unicodeName = text.getBytes(CharsetNames.UTF_8);
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException("FATAL: UTF-8 encoding not supported.", e);
}
}
/**
* Assemble as unicode extension from the name/comment and
* encoding of the original zip entry.
*
* @param text The file name or comment.
* @param bytes The encoded of the filename or comment in the zip
* file.
*/
protected AbstractUnicodeExtraField(final String text, final byte[] bytes) {
this(text, bytes, 0, bytes.length);
}
private void assembleData() {
if (unicodeName == null) {
return;
}
data = new byte[5 + unicodeName.length];
// version 1
data
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>[0] = 0x01;
System.arraycopy(ZipLong.getBytes(nameCRC32), 0, data, 1, 4);
System.arraycopy(unicodeName, 0, data, 5, unicodeName.length);
}
/**
* @return The CRC32 checksum of the filename or comment as
* encoded in the central directory of the zip file.
*/
public long getNameCRC32() {
return nameCRC32;
}
/**
* @param nameCRC32 The CRC32 checksum of the filename as encoded
* in the central directory of the zip file to set.
*/
public void setNameCRC32(final long nameCRC32) {
this.nameCRC32 = nameCRC32;
data = null;
}
/**
* @return The UTF-8 encoded name.
*/
public byte[] getUnicodeName() {
byte[] b = null;
if (unicodeName != null) {
b = new byte[unicodeName.length];
System.arraycopy(unicodeName, 0, b, 0, b.length);
}
return b;
}
/**
* @param unicodeName The UTF-8 encoded name to set.
*/
public void setUnicodeName(final byte[] unicodeName) {
if (unicodeName != null) {
this.unicodeName = new byte[unicodeName.length];
System.arraycopy(unicodeName, 0, this.unicodeName, 0,
unicodeName.length);
} else {
this.unicodeName = null;
}
data = null;
}
@Override
public byte[] getCentralDirectoryData() {
if (data == null) {
this.assembleData();
}
byte[] b = null;
if (data != null) {
b = new byte[data.length];
System.arraycopy(data, 0, b, 0, b.length);
}
return b;
}
@Override
public ZipShort getCentralDirectoryLength() {
if (data == null) {
assembleData();
}
return new ZipShort(data != null ? data.length : 0);
}
@Override
public byte[] getLocalFileDataData() {
return getCentralDirectoryData();
}
@Override
public ZipShort getLocalFileDataLength() {
return getCentralDirectoryLength();
}
@Override
public void parseFromLocalFileData(final byte[] buffer, final int offset, final int length)
throws ZipException {
if (length < 5) {
throw new ZipException("UniCode path extra data must have at least 5 bytes.");
}
final int version = buffer[offset];
if (version != 0x01) {
throw new ZipException("Unsupported version [" + version
+ "] for UniCode path extra data.");
}
nameCRC32 = ZipLong.getValue(buffer, offset + 1);
unicodeName = new byte[length - 5];
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> System.arraycopy(buffer, offset + 5, unicodeName, 0, length - 5);
data = null;
}
/**
* Doesn't do anything special since this class always uses the
* same data in central directory and local file data.
*/
@Override
public void parseFromCentralDirectoryData(final byte[] buffer, final int offset,
final int length)
throws ZipException {
parseFromLocalFileData(buffer, offset, length);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> IOUtils.readFully(in, result);
results.add(result);
}
}
assertArrayEquals(results.get(0), file1Contents);
assertArrayEquals(results.get(1), file2Contents);
}
/**
* Simple unarchive test. Asserts nothing.
* @throws Exception
*/
@Test
public void testZipUnarchive() throws Exception {
final File input = getFile("bla.zip");
final InputStream is = new FileInputStream(input);
final ArchiveInputStream in = new ArchiveStreamFactory().createArchiveInputStream("zip", is);
final ZipArchiveEntry entry = (ZipArchiveEntry)in.getNextEntry();
final OutputStream out = new FileOutputStream(new File(dir, entry.getName()));
IOUtils.copy(in, out);
out.close();
in.close();
}
/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/COMPRESS-208"
* >COMPRESS-208</a>.
*/
@Test
public void testSkipsPK00Prefix() throws Exception {
final File input = getFile("COMPRESS-208.zip");
final ArrayList<String> al = new ArrayList<>();
al.add("test1.xml");
al.add("test2.xml");
try (InputStream is = new FileInputStream(input)) {
checkArchiveContent(new ZipArchiveInputStream(is), al);
}
}
/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/COMPRESS-93"
* >COMPRESS-93</a>.
*/
@Test
public void testSupportedCompressionMethod() throws IOException {
/*
ZipFile bla = new ZipFile(getFile("bla.zip"));
assertTrue(bla.canReadEntryData(bla.getEntry("test1.xml")));
bla.close();
*/
final ZipFile moby = new ZipFile(getFile("moby.zip"));
final ZipArchiveEntry entry = moby.getEntry("README");
assertEquals("method", ZipMethod.TOKENIZATION.getCode(), entry.getMethod());
assertFalse(moby.canReadEntryData(entry));
moby.close();
}
/**
* Test case for being able to skip an entry in an
* {@link ZipArchiveInputStream} even if the compression method of that
* entry is unsupported.
*
* @see <a href="https://issues.apache.org/jira/browse/COMPRESS-93"
* >COMPRESS-93</a>
*/
@Test
public void testSkipEntryWithUnsupportedCompressionMethod()
throws IOException {
try (ZipArchiveInputStream zip = new ZipArchiveInputStream(new FileInputStream(getFile("moby.zip")))) {
final ZipArchiveEntry entry = zip.getNextZipEntry();
assertEquals("method", ZipMethod.TOKENIZATION.getCode(), entry.getMethod());
assertEquals("README", entry.getName());
assertFalse(zip.canReadEntryData(entry));
try {
assertNull(
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>zip.getNextZipEntry());
} catch (final IOException e) {
e.printStackTrace();
fail("COMPRESS-93: Unable to skip an unsupported zip entry");
}
}
}
/**
* Checks if all entries from a nested archive can be read.
* The archive: OSX_ArchiveWithNestedArchive.zip contains:
* NestedArchiv.zip and test.xml3.
*
* The nested archive: NestedArchive.zip contains test1.xml and test2.xml
*
* @throws Exception
*/
@Test
public void testListAllFilesWithNestedArchive() throws Exception {
final File input = getFile("OSX_ArchiveWithNestedArchive.zip");
final List<String> results = new ArrayList<>();
final List<ZipException> expectedExceptions = new ArrayList<>();
final InputStream is = new FileInputStream(input);
ArchiveInputStream in = null;
try {
in = new ArchiveStreamFactory().createArchiveInputStream("zip", is);
ZipArchiveEntry entry = null;
while ((entry = (ZipArchiveEntry) in.getNextEntry()) != null) {
results.add(entry.getName());
final ArchiveInputStream nestedIn = new ArchiveStreamFactory().createArchiveInputStream("zip", in);
try {
ZipArchiveEntry nestedEntry = null;
while ((nestedEntry = (ZipArchiveEntry) nestedIn.getNextEntry()) != null) {
results.add(nestedEntry.getName());
}
} catch (ZipException ex) {
// expected since you cannot create a final ArchiveInputStream from test3.xml
expectedExceptions.add(ex);
}
// nested stream must not be closed here
}
} finally {
if (in != null) {
in.close();
}
}
is.close();
assertTrue(results.contains("NestedArchiv.zip"));
assertTrue(results.contains("test1.xml"));
assertTrue(results.contains("test2.xml"));
assertTrue(results.contains("test3.xml"));
assertEquals(1, expectedExceptions.size());
}
@Test
public void testDirectoryEntryFromFile() throws Exception {
final File[] tmp = createTempDirAndFile();
File archive = null;
ZipArchiveOutputStream zos = null;
ZipFile zf = null;
try {
archive = File.createTempFile("test.", ".zip", tmp[0]);
archive.deleteOnExit();
zos = new ZipArchiveOutputStream(archive);
final long beforeArchiveWrite = tmp[0].lastModified();
final ZipArchiveEntry in = new ZipArchiveEntry(tmp[0], "foo");
zos.putArchiveEntry(in);
zos.closeArchiveEntry();
zos.close();
zos = null;
zf = new ZipFile(archive);
final ZipArchiveEntry out = zf.getEntry("foo/");
assertNotNull(out);
assertEquals("foo/", out.getName());
assertEquals(0, out.getSize());
// ZIP stores time with a granularity of 2 seconds
assertEquals(beforeArchiveWrite / 2000,
out.getLast
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>ModifiedDate().getTime() / 2000);
assertTrue(out.isDirectory());
} finally {
ZipFile.closeQuietly(zf);
if (zos != null) {
zos.close();
}
tryHardToDelete(archive);
tryHardToDelete(tmp[1]);
rmdir(tmp[0]);
}
}
@Test
public void testExplicitDirectoryEntry() throws Exception {
final File[] tmp = createTempDirAndFile();
File archive = null;
ZipArchiveOutputStream zos = null;
ZipFile zf = null;
try {
archive = File.createTempFile("test.", ".zip", tmp[0]);
archive.deleteOnExit();
zos = new ZipArchiveOutputStream(archive);
final long beforeArchiveWrite = tmp[0].lastModified();
final ZipArchiveEntry in = new ZipArchiveEntry("foo/");
in.setTime(beforeArchiveWrite);
zos.putArchiveEntry(in);
zos.closeArchiveEntry();
zos.close();
zos = null;
zf = new ZipFile(archive);
final ZipArchiveEntry out = zf.getEntry("foo/");
assertNotNull(out);
assertEquals("foo/", out.getName());
assertEquals(0, out.getSize());
assertEquals(beforeArchiveWrite / 2000,
out.getLastModifiedDate().getTime() / 2000);
assertTrue(out.isDirectory());
} finally {
ZipFile.closeQuietly(zf);
if (zos != null) {
zos.close();
}
tryHardToDelete(archive);
tryHardToDelete(tmp[1]);
rmdir(tmp[0]);
}
}
String first_payload = "ABBA";
String second_payload = "AAAAAAAAAAAA";
ZipArchiveEntryPredicate allFilesPredicate = new ZipArchiveEntryPredicate() {
@Override
public boolean test(final ZipArchiveEntry zipArchiveEntry) {
return true;
}
};
@Test
public void testCopyRawEntriesFromFile()
throws IOException {
final File[] tmp = createTempDirAndFile();
final File reference = createReferenceFile(tmp[0], Zip64Mode.Never, "expected.");
final File a1 = File.createTempFile("src1.", ".zip", tmp[0]);
final ZipArchiveOutputStream zos = new ZipArchiveOutputStream(a1);
zos.setUseZip64(Zip64Mode.Never);
createFirstEntry(zos).close();
final File a2 = File.createTempFile("src2.", ".zip", tmp[0]);
final ZipArchiveOutputStream zos1 = new ZipArchiveOutputStream(a2);
zos1.setUseZip64(Zip64Mode.Never);
createSecondEntry(zos1).close();
final ZipFile zf1 = new ZipFile(a1);
final ZipFile zf2 = new ZipFile(a2);
final File fileResult = File.createTempFile("file-actual.", ".zip", tmp[0]);
final ZipArchiveOutputStream zos2 =
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> new ZipArchiveOutputStream(fileResult);
zf1.copyRawEntries(zos2, allFilesPredicate);
zf2.copyRawEntries(zos2, allFilesPredicate);
zos2.close();
// copyRawEntries does not add superfluous zip64 header like regular zip output stream
// does when using Zip64Mode.AsNeeded so all the source material has to be Zip64Mode.Never,
// if exact binary equality is to be achieved
assertSameFileContents(reference, fileResult);
zf1.close();
zf2.close();
}
@Test
public void testCopyRawZip64EntryFromFile()
throws IOException {
final File[] tmp = createTempDirAndFile();
final File reference = File.createTempFile("z64reference.", ".zip", tmp[0]);
final ZipArchiveOutputStream zos1 = new ZipArchiveOutputStream(reference);
zos1.setUseZip64(Zip64Mode.Always);
createFirstEntry(zos1);
zos1.close();
final File a1 = File.createTempFile("zip64src.", ".zip", tmp[0]);
final ZipArchiveOutputStream zos = new ZipArchiveOutputStream(a1);
zos.setUseZip64(Zip64Mode.Always);
createFirstEntry(zos).close();
final ZipFile zf1 = new ZipFile(a1);
final File fileResult = File.createTempFile("file-actual.", ".zip", tmp[0]);
final ZipArchiveOutputStream zos2 = new ZipArchiveOutputStream(fileResult);
zos2.setUseZip64(Zip64Mode.Always);
zf1.copyRawEntries(zos2, allFilesPredicate);
zos2.close();
assertSameFileContents(reference, fileResult);
zf1.close();
}
@Test
public void testUnixModeInAddRaw() throws IOException {
final File[] tmp = createTempDirAndFile();
final File a1 = File.createTempFile("unixModeBits.", ".zip", tmp[0]);
final ZipArchiveOutputStream zos = new ZipArchiveOutputStream(a1);
final ZipArchiveEntry archiveEntry = new ZipArchiveEntry("fred");
archiveEntry.setUnixMode(0664);
archiveEntry.setMethod(ZipEntry.DEFLATED);
zos.addRawArchiveEntry(archiveEntry, new ByteArrayInputStream("fud".getBytes()));
zos.close();
final ZipFile zf1 = new ZipFile(a1);
final ZipArchiveEntry fred = zf1.getEntry("fred");
assertEquals(0664, fred.getUnixMode());
zf1.close();
}
private File createReferenceFile(final File directory, final Zip64Mode zipMode, final String prefix) throws IOException {
final File reference = File.createTempFile(prefix, ".zip", directory);
final ZipArchiveOutputStream zos = new ZipArchiveOutputStream(reference);
zos.setUseZip64(zip
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>Mode);
createFirstEntry(zos);
createSecondEntry(zos);
zos.close();
return reference;
}
private ZipArchiveOutputStream createFirstEntry(final ZipArchiveOutputStream zos) throws IOException {
createArchiveEntry(first_payload, zos, "file1.txt");
return zos;
}
private ZipArchiveOutputStream createSecondEntry(final ZipArchiveOutputStream zos) throws IOException {
createArchiveEntry(second_payload, zos, "file2.txt");
return zos;
}
private void assertSameFileContents(final File expectedFile, final File actualFile) throws IOException {
final int size = (int) Math.max(expectedFile.length(), actualFile.length());
final ZipFile expected = new ZipFile(expectedFile);
final ZipFile actual = new ZipFile(actualFile);
final byte[] expectedBuf = new byte[size];
final byte[] actualBuf = new byte[size];
final Enumeration<ZipArchiveEntry> actualInOrder = actual.getEntriesInPhysicalOrder();
final Enumeration<ZipArchiveEntry> expectedInOrder = expected.getEntriesInPhysicalOrder();
while (actualInOrder.hasMoreElements()){
final ZipArchiveEntry actualElement = actualInOrder.nextElement();
final ZipArchiveEntry expectedElement = expectedInOrder.nextElement();
assertEquals( expectedElement.getName(), actualElement.getName());
// Don't compare timestamps since they may vary;
// there's no support for stubbed out clock (TimeSource) in ZipArchiveOutputStream
assertEquals( expectedElement.getMethod(), actualElement.getMethod());
assertEquals( expectedElement.getGeneralPurposeBit(), actualElement.getGeneralPurposeBit());
assertEquals( expectedElement.getCrc(), actualElement.getCrc());
assertEquals( expectedElement.getCompressedSize(), actualElement.getCompressedSize());
assertEquals( expectedElement.getSize(), actualElement.getSize());
assertEquals( expectedElement.getExternalAttributes(), actualElement.getExternalAttributes());
assertEquals( expectedElement.getInternalAttributes(), actualElement.getInternalAttributes());
final InputStream actualIs = actual.getInputStream(actualElement);
final InputStream expectedIs = expected.getInputStream(expectedElement);
IOUtils.readFully(expectedIs, expectedBuf);
IOUtils.readFully(actualIs, actualBuf);
expectedIs.close();
actualIs.close();
Assert.assertArrayEquals(expectedBuf, actualBuf); // Buffers are larger than payload. dont care
}
expected.close();
actual.close();
}
private void createArchiveEntry(final String payload, final ZipArchiveOutputStream zos, final String name)
throws IOException {
final ZipArchiveEntry in = new ZipArchiveEntry(name);
zos.putArchiveEntry(in);
zos.write(payload.getBytes());
zos.closeArchiveEntry();
}
@Test
public void testFileEntryFromFile() throws Exception {
final File[] tmp = createTempDirAndFile();
File archive = null;
ZipArchiveOutputStream zos = null;
ZipFile zf = null;
FileInputStream fis = null;
try {
archive =
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
/**
* Creates Archive {@link ArchiveInputStream}s and {@link ArchiveOutputStream}s.
*
* @since 1.13
*/
public interface ArchiveStreamProvider {
/**
* Creates an archive input stream from an archiver name and an input
* stream.
*
* @param name
* the archive name, i.e.
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#AR},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#ARJ},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#ZIP},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#TAR},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#JAR},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#CPIO},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#DUMP}
* or
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#SEVEN_Z}
* @param in
* the input stream
* @param encoding
* encoding name or null for the default
* @return the archive input stream
* @throws ArchiveException
* if the archiver name is not known
* @throws StreamingNotSupportedException
* if the format cannot be read from a stream
* @throws IllegalArgumentException
* if the archiver name or stream is null
*/
ArchiveInputStream createArchiveInputStream(final String name, final InputStream in, final String encoding)
throws ArchiveException;
/**
* Creates an archive output stream from an archiver name and an output
* stream.
*
* @param name
* the archive name, i.e.
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#AR},
* {@value org.apache.commons
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>.compress.archivers.ArchiveStreamFactory#ZIP},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#TAR},
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#JAR}
* or
* {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#CPIO}
* @param out
* the output stream
* @param encoding
* encoding name or null for the default
* @return the archive output stream
* @throws ArchiveException
* if the archiver name is not known
* @throws StreamingNotSupportedException
* if the format cannot be written to a stream
* @throws IllegalArgumentException
* if the archiver name or stream is null
*/
ArchiveOutputStream createArchiveOutputStream(final String name, final OutputStream out, final String encoding)
throws ArchiveException;
/**
* Gets all the input stream archive names for this provider
*
* @return all the input archive names for this provider
*/
Set<String> getInputStreamArchiveNames();
/**
* Gets all the output stream archive names for this provider
*
* @return all the output archive names for this provider
*/
Set<String> getOutputStreamArchiveNames();
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> code from the jRPM project (jrpm.sourceforge.net)</p>
*/
public class CpioArchiveOutputStream extends ArchiveOutputStream implements
CpioConstants {
private CpioArchiveEntry entry;
private boolean closed = false;
/** indicates if this archive is finished */
private boolean finished;
/**
* See {@link CpioArchiveEntry#setFormat(short)} for possible values.
*/
private final short entryFormat;
private final HashMap<String, CpioArchiveEntry> names =
new HashMap<>();
private long crc = 0;
private long written;
private final OutputStream out;
private final int blockSize;
private long nextArtificalDeviceAndInode = 1;
/**
* The encoding to use for filenames and labels.
*/
private final ZipEncoding zipEncoding;
// the provided encoding (for unit tests)
final String encoding;
/**
* Construct the cpio output stream with a specified format, a
* blocksize of {@link CpioConstants#BLOCK_SIZE BLOCK_SIZE} and
* using ASCII as the file name encoding.
*
* @param out
* The cpio stream
* @param format
* The format of the stream
*/
public CpioArchiveOutputStream(final OutputStream out, final short format) {
this(out, format, BLOCK_SIZE, CharsetNames.US_ASCII);
}
/**
* Construct the cpio output stream with a specified format using
* ASCII as the file name encoding.
*
* @param out
* The cpio stream
* @param format
* The format of the stream
* @param blockSize
* The block size of the archive.
*
* @since 1.1
*/
public CpioArchiveOutputStream(final OutputStream out, final short format,
final int blockSize) {
this(out, format, blockSize, CharsetNames.US_ASCII);
}
/**
* Construct the cpio output stream with a specified format using
* ASCII as the file name encoding.
*
* @param out
* The cpio stream
* @param format
* The format of the stream
* @param blockSize
* The block size of the archive.
* @param encoding
* The encoding of file names to write - use null for
* the platform's default.
*
* @since 1.6
*/
public CpioArchiveOutputStream(final OutputStream out, final short format,
final int blockSize, final String encoding) {
this.out = out;
switch (format) {
case FORMAT_NEW:
case FORMAT_NEW_CRC:
case FORMAT_OLD_ASCII:
case FORMAT_OLD_BINARY:
break;
default:
throw new IllegalArgumentException("Unknown format: "+format);
}
this.entryFormat = format;
this.blockSize = blockSize;
this.encoding = encoding;
this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
}
/**
* Construct the cpio output stream. The format for this CPIO stream is
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> the
* "new" format using ASCII encoding for file names
*
* @param out
* The cpio stream
*/
public CpioArchiveOutputStream(final OutputStream out) {
this(out, FORMAT_NEW);
}
/**
* Construct the cpio output stream. The format for this CPIO stream is the
* "new" format.
*
* @param out
* The cpio stream
* @param encoding
* The encoding of file names to write - use null for
* the platform's default.
* @since 1.6
*/
public CpioArchiveOutputStream(final OutputStream out, final String encoding) {
this(out, FORMAT_NEW, BLOCK_SIZE, encoding);
}
/**
* Check to make sure that this stream has not been closed
*
* @throws IOException
* if the stream is already closed
*/
private void ensureOpen() throws IOException {
if (this.closed) {
throw new IOException("Stream closed");
}
}
/**
* Begins writing a new CPIO file entry and positions the stream to the
* start of the entry data. Closes the current entry if still active. The
* current time will be used if the entry has no set modification time and
* the default header format will be used if no other format is specified in
* the entry.
*
* @param entry
* the CPIO cpioEntry to be written
* @throws IOException
* if an I/O error has occurred or if a CPIO file error has
* occurred
* @throws ClassCastException if entry is not an instance of CpioArchiveEntry
*/
@Override
public void putArchiveEntry(final ArchiveEntry entry) throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
final CpioArchiveEntry e = (CpioArchiveEntry) entry;
ensureOpen();
if (this.entry != null) {
closeArchiveEntry(); // close previous entry
}
if (e.getTime() == -1) {
e.setTime(System.currentTimeMillis() / 1000);
}
final short format = e.getFormat();
if (format != this.entryFormat){
throw new IOException("Header format: "+format+" does not match existing format: "+this.entryFormat);
}
if (this.names.put(e.getName(), e) != null) {
throw new IOException("duplicate entry: " + e.getName());
}
writeHeader(e);
this.entry = e;
this.written = 0;
}
private void writeHeader(final CpioArchiveEntry e) throws IOException {
switch (e.getFormat()) {
case FORMAT_NEW:
out.write(ArchiveUtils.toAsciiBytes(MAGIC_NEW));
count(6);
writeNewEntry(e);
break;
case FORMAT_NEW_CRC:
out.write(ArchiveUtils.toAsciiBytes(MAGIC_NEW_CRC));
count(6);
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> pad(blockSize - lengthOfLastBlock);
}
finished = true;
}
/**
* Closes the CPIO output stream as well as the stream being filtered.
*
* @throws IOException
* if an I/O error has occurred or if a CPIO file error has
* occurred
*/
@Override
public void close() throws IOException {
if(!finished) {
finish();
}
if (!this.closed) {
out.close();
this.closed = true;
}
}
private void pad(final int count) throws IOException{
if (count > 0){
final byte buff[] = new byte[count];
out.write(buff);
count(count);
}
}
private void writeBinaryLong(final long number, final int length,
final boolean swapHalfWord) throws IOException {
final byte tmp[] = CpioUtil.long2byteArray(number, length, swapHalfWord);
out.write(tmp);
count(tmp.length);
}
private void writeAsciiLong(final long number, final int length,
final int radix) throws IOException {
final StringBuilder tmp = new StringBuilder();
String tmpStr;
if (radix == 16) {
tmp.append(Long.toHexString(number));
} else if (radix == 8) {
tmp.append(Long.toOctalString(number));
} else {
tmp.append(Long.toString(number));
}
if (tmp.length() <= length) {
final long insertLength = length - tmp.length();
for (int pos = 0; pos < insertLength; pos++) {
tmp.insert(0, "0");
}
tmpStr = tmp.toString();
} else {
tmpStr = tmp.substring(tmp.length() - length);
}
final byte[] b = ArchiveUtils.toAsciiBytes(tmpStr);
out.write(b);
count(b.length);
}
/**
* Writes an ASCII string to the stream followed by \0
* @param str the String to write
* @throws IOException if the string couldn't be written
*/
private void writeCString(final String str) throws IOException {
final ByteBuffer buf = zipEncoding.encode(str);
final int len = buf.limit() - buf.position();
out.write(buf.array(), buf.arrayOffset(), len);
out.write('\0');
count(len + 1);
}
/**
* Creates a new ArchiveEntry. The entryName must be an ASCII encoded string.
*
* @see org.apache.commons.compress.archivers.ArchiveOutputStream#createArchiveEntry(java.io.File, java.lang.String)
*/
@Override
public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName)
throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
return new CpioArchiveEntry(inputFile, entryName);
}
}
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS>
* @param offset the start offset
* @param length the number of bytes in the array from offset
* @throws java.util.zip.ZipException on error
*/
@Override
public void parseFromLocalFileData(
final byte[] data, int offset, final int length
) throws ZipException {
reset();
final int len = offset + length;
setFlags(data[offset++]);
if (bit0_modifyTimePresent) {
modifyTime = new ZipLong(data, offset);
offset += 4;
}
// Notice the extra length check in case we are parsing the shorter
// central data field (for both access and create timestamps).
if (bit1_accessTimePresent && offset + 4 <= len) {
accessTime = new ZipLong(data, offset);
offset += 4;
}
if (bit2_createTimePresent && offset + 4 <= len) {
createTime = new ZipLong(data, offset);
offset += 4;
}
}
/**
* Doesn't do anything special since this class always uses the
* same parsing logic for both central directory and local file data.
*/
@Override
public void parseFromCentralDirectoryData(
final byte[] buffer, final int offset, final int length
) throws ZipException {
reset();
parseFromLocalFileData(buffer, offset, length);
}
/**
* Reset state back to newly constructed state. Helps us make sure
* parse() calls always generate clean results.
*/
private void reset() {
setFlags((byte) 0);
this.modifyTime = null;
this.accessTime = null;
this.createTime = null;
}
/**
* Sets flags byte. The flags byte tells us which of the
* three datestamp fields are present in the data:
* <pre>
* bit0 - modify time
* bit1 - access time
* bit2 - create time
* </pre>
* Only first 3 bits of flags are used according to the
* latest version of the spec (December 2012).
*
* @param flags flags byte indicating which of the
* three datestamp fields are present.
*/
public void setFlags(final byte flags) {
this.flags = flags;
this.bit0_modifyTimePresent = (flags & MODIFY_TIME_BIT) == MODIFY_TIME_BIT;
this.bit1_accessTimePresent = (flags & ACCESS_TIME_BIT) == ACCESS_TIME_BIT;
this.bit2_createTimePresent = (flags & CREATE_TIME_BIT) == CREATE_TIME_BIT;
}
/**
* Gets flags byte. The flags byte tells us which of the
* three datestamp fields are present in the data:
* <pre>
* bit0 - modify time
* bit1 - access time
* bit2 - create time
* </pre>
* Only first 3 bits of flags are used according to the
* latest version of the spec (De
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> @return ZipLong
*/
private static ZipLong dateToZipLong(final Date d) {
if (d == null) { return null; }
final long TWO_TO_32 = 0x100000000L;
final long l = d.getTime() / 1000;
if (l >= TWO_TO_32) {
throw new IllegalArgumentException("Cannot set an X5455 timestamp larger than 2^32: " + l);
}
return new ZipLong(l);
}
/**
* Returns a String representation of this class useful for
* debugging purposes.
*
* @return A String representation of this class useful for
* debugging purposes.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("0x5455 Zip Extra Field: Flags=");
buf.append(Integer.toBinaryString(ZipUtil.unsignedIntToSignedByte(flags))).append(" ");
if (bit0_modifyTimePresent && modifyTime != null) {
final Date m = getModifyJavaTime();
buf.append(" Modify:[").append(m).append("] ");
}
if (bit1_accessTimePresent && accessTime != null) {
final Date a = getAccessJavaTime();
buf.append(" Access:[").append(a).append("] ");
}
if (bit2_createTimePresent && createTime != null) {
final Date c = getCreateJavaTime();
buf.append(" Create:[").append(c).append("] ");
}
return buf.toString();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public boolean equals(final Object o) {
if (o instanceof X5455_ExtendedTimestamp) {
final X5455_ExtendedTimestamp xf = (X5455_ExtendedTimestamp) o;
// The ZipLong==ZipLong clauses handle the cases where both are null.
// and only last 3 bits of flags matter.
return ((flags & 0x07) == (xf.flags & 0x07)) &&
(modifyTime == xf.modifyTime || (modifyTime != null && modifyTime.equals(xf.modifyTime))) &&
(accessTime == xf.accessTime || (accessTime != null && accessTime.equals(xf.accessTime))) &&
(createTime == xf.createTime || (createTime != null && createTime.equals(xf.createTime)));
}
return false;
}
@Override
public int hashCode() {
int hc = (-123 * (flags & 0x07)); // only last 3 bits of flags matter
if (modifyTime != null) {
hc ^= modifyTime.hashCode();
}
if (accessTime != null) {
// Since accessTime is often same as modifyTime,
// this prevents them from XOR negating each other.
hc ^= Integer
Compress, 41
<FILEB>
<CHANGES>
return null;
<CHANGEE>
<CHANGES>
throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue()));
<CHANGEE>
<FILEE>
<FILEB>
}
try {
if (firstEntry) {
// split archives have a special signature before the
// first local file header - look for it and fail with
// the appropriate error message if this is a split
// archive.
readFirstLocalFileHeader(LFH_BUF);
} else {
readFully(LFH_BUF);
}
} catch (final EOFException e) {
return null;
}
final ZipLong sig = new ZipLong(LFH_BUF);
if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) {
hitCentralDirectory = true;
skipRemainderOfArchive();
<CHANGES>
<CHANGEE>
}
if (!sig.equals(ZipLong.LFH_SIG)) {
<CHANGES>
return null;
<CHANGEE>
}
int off = WORD;
current = new CurrentEntry();
final int versionMadeBy = ZipShort.getValue(LFH_BUF, off);
off += SHORT;
current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK);
final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(LFH_BUF, off);
final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames();
final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding;
current.hasDataDescriptor = gpFlag.usesDataDescriptor();
current.entry.setGeneralPurposeBit(gpFlag);
off += SHORT;
<FILEE>
<SCANS> start offset
* @param length the number of bytes in the array from offset
*
* @throws ZipException on error
*/
@Override
public void parseFromLocalFileData(final byte[] data, final int offset, final int length)
throws ZipException {
if (length != 0) {
throw new ZipException("JarMarker doesn't expect any data");
}
}
/**
* Doesn't do anything special since this class always uses the
* same data in central directory and local file data.
*/
@Override
public void parseFromCentralDirectoryData(final byte[] buffer, final int offset,
final int length)
throws ZipException {
parseFromLocalFileData(buffer, offset, length);
}
}